मैंने डेल्फी समुदाय संस्करण का उपयोग करके एक प्रोग्राम (फ़ायरमोनकी) लिखा है। मैं प्रोग्राम को साझा करना चाहता हूं, लेकिन मेरे मित्र जिस .exe फ़ाइल को डाउनलोड कर रहे हैं, उसे स्ट्रिंग्स को पुनः प्राप्त करने के लिए समय-समय पर एक टेक्स्ट फ़ाइल तक पहुंचना होगा। प्रोग्राम लिखते समय मैंने स्टार्टअप पर टेक्स्ट फ़ाइल लोड करने के लिए एक ईवेंट हैंडलर का उपयोग किया:

Tform3.formCreate (प्रेषक: विषय); ... असाइनफाइल (माईफाइल, ('सी:******* ***।टेक्स्ट)); ...

डिजाइन चरण के दौरान ठीक काम किया।

एक शौक़ीन व्यक्ति के रूप में, मैं अब खुद को अटका हुआ पाता हूँ। यदि मैं एक इंस्टॉलेशन प्रोग्राम बनाने के लिए INNO सेटअप कंपाइलर का उपयोग करता हूं, जिसे मैं करने की योजना बना रहा हूं, तो मेरे पास डेटा फ़ाइल के स्थान पर यह वही हार्डवेयर्ड संदर्भ ('C:*****) नहीं हो सकता। मुझे उपरोक्त कोड को बदलने की आवश्यकता है जैसे कि .exe फ़ाइल सहायक डेटाफ़ाइल का पता लगा सकती है, भले ही वह .exe फ़ाइल (और डेटाफ़ाइल) किसी और के पीसी पर समाप्त हो।

मैं यह कैसे कर सकता हूँ? यानी मुझे कौन सा कोड चाहिए (उपरोक्त के स्थान पर) यह सुनिश्चित करने के लिए कि मैं जो इंस्टॉलेशन प्रोग्राम सौंपता हूं वह एक .exe फ़ाइल स्थापित करेगा जो डेटा फ़ाइल को संदर्भित कर सकता है?

कोई मदद, बहुत सराहना की। अभी भी सीख रहा।

0
Mariner 28 अक्टूबर 2020, 09:49

4 जवाब

सबसे बढ़िया उत्तर

केवल पढ़ने के लिए पहुँच

यदि डेटा फ़ाइल हमेशा-पढ़ने के लिए मोड में खोली जानी चाहिए, तो सबसे आसान समाधान इसे *.exe फ़ाइल के बगल में रखना है। फिर, रनटाइम पर, आप गतिशील रूप से *.exe फ़ाइल का पथ ढूंढते हैं और डेटा फ़ाइल के पथ को खोजने के लिए इसे संशोधित करते हैं। उदाहरण के लिए,

uses
  IOUtils;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
begin
  FileName := TPath.Combine(ExtractFilePath(ParamStr(0)), 'data.txt');
  ShowMessage(TFile.ReadAllText(FileName, TEncoding.UTF8));
end;

ParamStr(0) में *.exe फ़ाइल का पथ शामिल है, जैसे

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\Project1.exe'

तब ExtractFilePath(ParamStr(0)) है

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\'

और, अंत में, TPath.Combine(ExtractFilePath(ParamStr(0)), 'data.txt') है

'C:\Users\Andreas Rejbrand\Documents\Embarcadero\Studio\Projects\test\Win32\Debug\data.txt'

सुनिश्चित करें कि इंस्टॉलर डेटा फ़ाइल को *.exe फ़ाइल के आगे रखता है।

पहुंच पढ़ें और लिखें

यदि हम एक सेटिंग फ़ाइल या किसी अन्य फ़ाइल के बारे में बात कर रहे हैं जिसे प्रत्येक उपयोगकर्ता को बदलने की आवश्यकता है (सॉफ़्टवेयर के माध्यम से), तो आप इसे *.exe फ़ाइल के बगल में नहीं रख सकते, क्योंकि *.exe फ़ाइल आमतौर पर प्रोग्राम फ़ाइलें फ़ोल्डर में रहती है, जो केवल पढ़ा जाता है। इसके अलावा, केवल एक प्रोग्राम फाइल फ़ोल्डर है, लेकिन संभवतः पीसी पर कई उपयोगकर्ता हैं, और प्रत्येक उपयोगकर्ता की अपनी प्रति होनी चाहिए।

समाधान यह है कि फ़ाइल को उपयोगकर्ता के स्वयं के फ़ोल्डरों में, विशेष रूप से, AppData फ़ोल्डर में सहेजा जाए:

FileName := TPath.GetHomePath + '\Mariner\My Word Processor App\Settings\settings.ini';

(पथ निर्माण के लिए एक अलग दृष्टिकोण का उपयोग करके)।

मेरे सिस्टम पर, यह बन जाता है

'C:\Users\Andreas Rejbrand\AppData\Roaming\Mariner\My Word Processor App\Settings\settings.ini'

आपके इंस्टॉलर (इनो सेटअप) में इस स्थान पर फ़ाइलें रखने के लिए अंतर्निहित समर्थन है।

4
Andreas Rejbrand 28 अक्टूबर 2020, 10:56

अपने लक्ष्य को प्राप्त करने के लिए आपके पास कई विकल्प हैं:

  1. सबसे आसान तब होता है जब आप अपनी डेटा फ़ाइलों को उसी फ़ोल्डर में रखते हैं जिसमें EXE फ़ाइल होती है। फिर आप पथ को गतिशील रूप से प्राप्त करने के लिए ExtractFilePath(ParamStr(0)) + 'NameOfFile.txt' का उपयोग कर सकते हैं।
    लेकिन अपनी फाइलों को लिखने के प्रति जागरूक रहें। यदि EXE को कहीं C:\Programs (x86) या C:\Programs में रखा गया है, तो आप केवल फाइलों को लिख सकते हैं जब प्रोग्राम एलिवेटेड (व्यवस्थापक अधिकारों के साथ) चलता है! इस समस्या से बचने के लिए, EXE को किसी फ़ोल्डर में सीधे C:\ के नीचे रखें।

  2. यदि आप अपनी डेटा फ़ाइलों को किसी अन्य फ़ोल्डर में रखना चाहते हैं, उदा. कहीं AppData में, आप इस कोड का उपयोग कर सकते हैं:

    uses
      SHFolder;
    
    const
      CSIDL_COMMON_APPDATA = $0023;
      CSIDL_MYMUSIC = $000D;
      CSIDL_MYPICTURES = $0027;
      CSIDL_MYVIDEO = $000E;
      CSIDL_PROGRAM_FILES = $0026;
      CSIDL_PROGRAM_FILES_COMMON = $002B;
      CSIDL_SYSTEM = $0025;
      CSIDL_WINDOWS = $0024;
    
    type
      TSpecialFolder = (
        // user folders
        sfUserAppData = CSIDL_APPDATA, // Anwendungsdaten: Ordner zur Ablage von Einstellungen für Anwendungsprogramme
        sfUserCookies = CSIDL_COOKIES, // Cookies
        sfUserDesktop = CSIDL_DESKTOPDIRECTORY, // Desktop
        sfUserDocuments = CSIDL_PERSONAL, // My files
        sfUserFavorites = CSIDL_FAVORITES, 
        sfUserIEHistory = CSIDL_HISTORY, // Internet history
        sfUserIECache = CSIDL_INTERNET_CACHE, // "Temporary Internet Files"
        sfUserLocalAppData = CSIDL_LOCAL_APPDATA,
        sfUserMusic = CSIDL_MYMUSIC, 
        sfUserNethood = CSIDL_NETHOOD, 
        sfUserPictures = CSIDL_MYPICTURES, 
        sfUserPrintHood = CSIDL_PRINTHOOD, 
        sfUserProfile = CSIDL_PROFILE, // User folder C:\Users\<Username>
        sfUserRecent = CSIDL_RECENT, 
        sfUserSendTo = CSIDL_SENDTO,
        sfUserStartMenuPrograms = CSIDL_PROGRAMS, // "Programs" in Startmenue
        sfUserStartMenu = CSIDL_STARTMENU, // Startmenue
        sfUserStartUp = CSIDL_STARTUP, // Startup in Startmenue
        sfUserTemplates = CSIDL_TEMPLATES,
        sfUserVideo = CSIDL_MYVIDEO, 
    
        // All Users folders
        sfCommonAppData = CSIDL_COMMON_APPDATA, 
        sfCommonDesktop = CSIDL_COMMON_DESKTOPDIRECTORY, 
        sfCommonDocuments = CSIDL_COMMON_DOCUMENTS,
        sfCommonFavorites = CSIDL_COMMON_FAVORITES,
        sfCommonFiles = CSIDL_PROGRAM_FILES_COMMON,
        sfCommonMusic = CSIDL_COMMON_MUSIC,
        sfCommonPictures = CSIDL_COMMON_PICTURES,
        sfCommonStartMenuPrograms = CSIDL_COMMON_PROGRAMS, // "Programs" in Startmenue
        sfCommonStartMenu = CSIDL_COMMON_STARTMENU, 
        sfCommonStartUp = CSIDL_COMMON_STARTUP, // Startup in Startmenue
        sfCommonVideo = CSIDL_COMMON_VIDEO,
    
        // system folders
        sfFonts = CSIDL_FONTS, 
        sfProgramFiles = CSIDL_PROGRAM_FILES,
        sfSystem32 = CSIDL_SYSTEM, 
        sfWindows = CSIDL_WINDOWS 
        );
    
    function GetSpecialFolder(const SpecialFolder: TSpecialFolder): string;
    const
      SHGFP_TYPE_CURRENT = 0;
    var
      Path: array [0 .. MAX_PATH] of char;
    begin
      if SUCCEEDED(SHGetFolderPath(0, Ord(SpecialFolder), 0, SHGFP_TYPE_CURRENT, @Path[0])) then
        result := Path
      else
        result := '';
    end;
    

    उदाहरण:

    GetSpecialFolder(sfUserAppData) + 'YourFolder\NameOfFile.txt'
    
0
Delphi Coder 28 अक्टूबर 2020, 11:21

यदि इसे केवल पढ़ने के लिए ही एक्सेस किया जाता है, तो आप इसे निष्पादन योग्य में संसाधन के रूप में जोड़ने पर भी विचार कर सकते हैं। जो तब आपको इंस्टॉलर की आवश्यकता के बिना इस निष्पादन योग्य को वितरित करने की अनुमति देगा।

डेल्फी डब्बलर का एक उदाहरण है, लेकिन मुझे यह थोड़ा भ्रमित करने वाला लगा। मैं वैसे भी इससे लिंक (पीडीएफ) करूंगा।

1
dummzeuch 28 अक्टूबर 2020, 13:42

आप उपयोगकर्ता को उस स्थान का चयन करने दे सकते हैं जहां फ़ाइल को सहेजना है। यदि फ़ाइल प्रत्येक व्यक्तिगत उपयोगकर्ता के लिए है या CommonAppData यदि फ़ाइल को विभिन्न उपयोगकर्ताओं के बीच साझा किया जाना है, तो AppData फ़ोल्डर का प्रस्ताव करना।

जब उपयोग डेटा फ़ाइल गंतव्य का चयन करता है, तो आप इसे एक आईएनआई फ़ाइल में सहेज सकते हैं। INI फ़ाइल को उपयोगकर्ता से पूछे बिना, रजिस्ट्री में या AppData फ़ोल्डर या प्रोग्रामडेटा फ़ोल्डर में सहेजी गई INI फ़ाइल में संग्रहीत किया जा सकता है।

यहाँ उन विशेष फ़ोल्डरों पर हाथ पाने के लिए स्रोत कोड का एक टुकड़ा दिया गया है:

const
    SectionWindow            = 'Window';
    SectionData              = 'Data';
    CompanyFolder            = 'YourCompanyName';


constructor TForm1.Create(AOwner: TComponent);
    var
        CommonPath   : array [0..MAX_PATH] of Char;
        LocalPath    : array [0..MAX_PATH] of Char;
        LangFileName : String;
    begin
        SHGetFolderPath(0, CSIDL_COMMON_APPDATA, 0, SHGFP_TYPE_CURRENT, @CommonPath[0]);
        SHGetFolderPath(0, CSIDL_LOCAL_APPDATA,  0, SHGFP_TYPE_CURRENT, @LocalPath[0]);
        FIniSection     := SectionWindow;
        FIniSectionData := SectionData;
        FAppName        := ChangeFileExt(ExtractFileName(Application.ExeName), '');
        FCommonAppData  := IncludeTrailingPathDelimiter(CommonPath) +
                           CompanyFolder + '\' + FAppName + '\';
        FLocalAppData   := IncludeTrailingPathDelimiter(LocalPath) +
                           CompanyFolder + '\' + FAppName + '\';
        FIniFileName    := FLocalAppData + FAppName + '.ini';
        ForceDirectories(FCommonAppData);
        ForceDirectories(FLocalAppData);
        inherited Create(AOwner);
    end;
0
fpiette 28 अक्टूबर 2020, 16:33