LazarusCompleteGuide:5.3

From 흡혈양파의 번역工房
Revision as of 15:48, 28 February 2013 by Onionmixer (talk | contribs) (소스 수정)
Jump to navigation Jump to search

리소스 파일

리소스 파일은 프로그램의 실행에 필요한 읽기전용 외부 데이터를 보관하는 데에 사용된다. 리소스가 없는 유용한 프로그램이라면 무엇이든 쓸 수 있다. 이러한 리소스에는 그림, 오디오 데이터, XML 파일, 데이터베이스 파일, 도움말 파일 등이 있다. 해당 정보를 저장하기 위한 위치는 운영체제마다 다르기 때문에 신중하게 고려해야 한다. 일부 운영체제는-예: 리눅스-사용 중인 배포판에 따라 다르게 구성되는 경로를 필요로 하기도 한다. 이번 절에서 예제로 보여줄 유닛은 이러한 세부사항을 고려한다.


대부분 프로그램은 관리자 (또는 루트) 권한이 없이 실행된다. 이것이 바로 프로그램들이 어떤 사용자든 읽을 수 있는 위치에 데이터를 위치시켜야 하는 이유이다. 쓰기 접근은 항상 필요한 것은 아니다. 하지만 구성 파일은 읽기와 쓰기가 허용되는 위치에 보관되어야 한다.


MacOS X는 소프트웨어와 애플리케이션을 위한 데이터를 모두 포함하는 애플리케이션 번들로 작업하기 때문에 유닉스 시스템에서 예외가 된다. 즉, 리소스 파일이 번들의 일부가 되어야 함을 의미한다. 번들이 이동될 경우에도 애플리케이션은 여전히 기능을 계속할 필요가 있다. 번들에 대한 올바른 위치는 Core 와 Foundation 으로부터의 API 호출로 검색할 수 있다.

운영체제 리소스 파일의 최적 위치
Windows, Windows CE 실행 파일과 같은 디렉터리, 또는 그 하위디렉터리 중 하나.
Mac OS X 애플리케이션 번들 내부.
FreeBSD resource /usr/local/share/app_name
FreeBSD에서는 파일 저장에 /usr/share 디렉터리를 이용해선 안 된다.
기타 UNIX들 (Linux, Solaris 등) 고정되었으나 구성 가능한 위치. 주로 /usr/share/app_name 또는 /opt/app_name /usr/share /app_name 또는 /opt/app_name이 된다.
표 5.17: 권장하는 리소스 파일 보관 위치


아래 예제는 실행 가능 프로그램과 데이터 파일이 동일한 장소에 저장되는 (또는 MyDirectory + 'data' + PathDelim + 'myfile.dat' 와 같은 내용을 기반으로 한 디렉터리에 저장되는) 윈도우에 대한 솔루션을 보여준다. 유닉스 시스템에서는 구성 파일에서 명시하는 디렉터리에 보관된다. 구성 파일이 없거나 이 정보를 포함하지 않은 경우, 기본 디렉터리로 일관된 /usr/share/myapp 가 사용된다. 앞 절에서 논한 바와 같이 구성 파일의 경로는 프리 파스칼 RTL의 GetAppConfigFile 함수를 통해 얻을 수 있다.


myApp 로부터 프로그램 이름을 변경한 후 자신의 프로그램에서 아래의 완전한 유닛을 사용할 수 있다:

unit appsettings;

interface

{$ifdef fpc}
  {$mode delphi}{$H+}
{$endif}
uses
{$Iifdef MSWindows}
  Windows,
{$endif}
{$ifdef Darwin}
  MacOSAll,
{$endif}
  Classes, SysUtils, Forms, IniFiles, constants;

type
  { TConfigurations }
  TConfigurations = class(TObject)
  private
     ConfigFilePath: String;
     MyDirectory: String;
  public
     constructor Create;
     destructor Destroy; Override;
     function GetResourcesDir: string;
     procedure ReadFromFile(Sender: TObject);
     procedure Save(Sender: TObject);
  end;

var
  vConfigurations: TConfigurations;

implementation

const
  DefaultDirectory  = '/usr/share/myapp/';
  SectionGeneral    = 'General';
  SectionUnix       = 'UNIX';
  IdentMyDirectory  = 'MyDirectory';
  BundleResourcesDirectory = '/Contents/Resources/';

{ TConfigurations }
constructor TConfigurations.Create;
begin
  ConfigFilePath := GetAppConfigDirUTF8(False)  + 'myapp.ini';
  ReadFromFile(NIL);
end;

destructor TConfigurations.Destroy;
begin
  Save(NIL);
  inherited Destroy;
end;

function TConfigurations.GetResourcesDir: string;
{$ifdef Darwin}
var
  pathRef: CFURLRef;
  pathCFStr: CFStringRef;
  pathStr: shortstring;
{$endif}
begin
{$ifdef UNIX}
{$ifdef Darwin}
  pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle());
  pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle);
  CFStringGetPascalString(pathCFStr, @pathStr,
     255, FStringGetSystemEncoding());
  CFRelease(pathRef);
  CFRelease(pathCFStr);

  Result := pathStr + BundleResourcesDirectory;
{$else}
  if MyDirectory  = '' then Result := DefaultDirectory
     else Result := MyDirectory;
{$endif}
{$endif}

{$ifdef Windows}
  Result := ExtractFilePath(Application.EXEName);
{$endif}
end;

procedure TConfigurations.Save(Sender: TObject);
var
  MyFile: TIniFile;
begin
  MyFile := TIniFile.Create(UTF8ToSys(ConfigFilePath));
  try
     MyFile.WriteString(SectionUnix, IdentMyDirectory, MyDirectory);
  finally
     MyFile.Free;
  end;
end;

procedure TConfigurations.ReadFromFile(Sender: TObject);
var
  MyFile: TIniFile;
begin
  MyFile := TIniFile.Create(ConfigFilePath);
  try
     // Here other configurations can be read
     MyDirectory := MyFile.ReadString(SectionUnix, IdentMyDirectory, '');
  finally
     MyFile.Free;
  end;
end;

initialization
  vConfigurations := TConfigurations.Create;

finalization
  FreeAndNil(vConfigurations);
end.
"


#220, 327~327 (5.3) !!
"Here is an example code snippet which uses a routine from this unit:"
"
// $$...
bmp := TBitmap.Create
try
   bmp.LoadFromFile(vConfigurations.GetResourcesDir() + 'MyBitmap.bmp');
finally
   bmp.Free;
end;


.ini 파일로 작업하는 것보다 좀 더 윈도우적인 방식은 레지스트리(registry)에 데이터를 쓰고 그로부터 읽는 것이다. 프리 파스칼은 Registry 유닛에 이를 위한 특수 루틴을 제공한다. 레지스트리를 사용할 때는 시스템으로부터 프로그램을 삭제 시 쓰레기(garbage)를 남기지 않도록 매우 주의를 기울여야 한다. 그래서 Nullsoft Installation System(NSIS)을 기반으로 한 적절한 설치 프로그램을 사용하는 것인데, 관련 내용은


http://nsis.sourceforge.net/Main_Page


위의 주소 또는 아래 주소에서 InnoSetup을 참고한다:


http://www.jrsoftware.org/isinfo.php


레지스트리는 윈도우에서만 이용할 수 있기 때문에 모든 루틴 호출과 Registry 유닛 자체로의 링크는 조건부 컴파일 섹션 {$ifdef MSWindows}에 위치해야 하는 반면, .ini 파일은 진정한 크로스 플랫폼이라 할 수 있다.