Memo and create file and folder? - delphi

I'm new to Delphi and i'm a french user so sorry for my bad english...
So it is possible to create a file written in TMemo?
test.txt
dir1/dir2/text.txt
dir3/
My TMemo there are 3 lines, so I would like to take the first line and create the file test.txt in the current directory ..
2nd line: create a folder
3rd line: create a folder again+files.txt
etc ...
I think to use mkdir or ForceDirectories to create Directory and files? etc...
So my conclusion was to automate it.
You can help me please?
a small image so you can see:

With Program and on ButtonClick event
If I have understood the question correctly, this will
Create an empty text file in the application directory with the filename as per Memo Line 1
Create Folders as per Memo Line 2 and in the "base directory" per the edit
Create a Folder and empty TextFile as per Memo Line 3 again in the "base directory"
procedure TForm1.Button1Click(Sender: TObject);
var
Path: String;
F: TextFile;
begin
// Create File in current directory
Path := ExtractFilePath(ParamStr(0)) + Memo1.Lines.Strings[0];
if not FileExists(Path) then
begin
AssignFile(F, Path);
Rewrite(F);
//Writeln(F, 'text to write to file');
CloseFile(F);
end;
// Create Directories
Path := IncludeTrailingPathDelimiter(edPath.Text) + Memo1.Lines.Strings[1];
if not DirectoryExists(Path) then
ForceDirectories(Path);
// Create Directory and File
Path := IncludeTrailingPathDelimiter(edPath.Text) + Memo1.Lines.Strings[2];
if not DirectoryExists(ExtractFilePath(Path)) then
ForceDirectories(ExtractFilePath(Path));
if not FileExists(Path) then
begin
AssignFile(F, Path);
Rewrite(F);
//Writeln(F, 'text to write to file');
CloseFile(F);
end;
end;
Obviously needs significantly more error checking determining if paths valid and files / directories created etc...

Edit: code in browser so have no idea if it works but really is a simple thing to do.
You should only use a TMemo if you want to display the data before you save it, because the task of a visual control is to display something. But if you only want to use the Items propery of the TMemo for collecting strings and then save them to file you should use a TStringList instead:
var
i: Integer;
sl: TStringList;
begin
sl := TStringList.Create;
try
for i := 0 to Memo1.Lines.Count-1 do
sl.Add(Memo1.Lines[i]);
sl.SaveToFile(sl[1]);
finally
sl.free;
end;
end;
You may also like this thread: http://www.tek-tips.com/viewthread.cfm?qid=678231
EDIT2:
Memo1.Lines.SaveToFile(edit1.text + Memo1.Lines[0]);
Provided that Edit Control is named Edit1 and has your base path and first line of the TMemo has the file name. The other bit you need is an Event and by that I mean if you doubleclick your TMemo instance it will be the event that will start the cascade for saving the file.
As you see it is very easy and there are other ways such as SaveDialog that can make it much easier still. but hope this answers your question.

Related

How to create a folder and a txt file in Delphi

How do I create a new folder in the internal storage (?) of Android (I want say, the main folder that has all the subfolders ... Whatsapp, DCIM, pictures, Ringtones, Alarms ..) and create a new .txt file inside in this folder.
I want to create a .txt file and I need the user to plug the USB cable into their computer, access the device, enter the folder my application creates, and copy this file to their desktop.
I tried this code to create the file:
procedure TF_start.Button2Click(Sender: TObject);
var
output_text: string;
arquivo: TextFile;
begin
output_text := 'test';
TFile.WriteAllText(TPath.Combine(TPath.GetDocumentsPath, 'test.txt'), 'content');
ReWrite(arquivo);
WriteLn(arquivo, output_text);
CloseFile(arquivo);
end;
But it does not work.
To get the internal storage(?) path, I found this code:
P := '/storage/';
if (FindFirst(P + '*', faAnyFile, Sr) = 0) then
repeat
Memo1.Lines.Add(Sr.Name);
until (FindNext(Sr) <> 0);
FindClose(Sr);
But I can't understand how it works, so I can't even use it.
I also found this link, but I didn't find any function that returns me the "general" directory path I want to create a folder.
The functions System.IOUtils.TPath.GetHomePath(), and System.IOUtils.TPath.GetDocumentsPath() do not return me the correct path.
System.SysUtils.GetHomePath() return -> /data/user/0/com.embarcadero.app/cache
System.IOUtils.TPath.GetDocumentsPath() return -> /data/com.embarcadero.app-1/lib/arm
#edit
Using the #Remy Lebeau code and this code I managed to get to this point.
The problem is that the code to update the directory with the files does nothing
Use System.IOUtils, Androidapi.Helpers, Androidapi.Jni.Media, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText;
//Button
procedure TF_start.Button2Click(Sender: TObject);
var
path_file output_text: string;
begin
path_file := TPath.Combine(System.IOUtils.TPath.GetSharedDownloadsPath, 'Folder_app');
output_text := 'test';
if not TDirectory.Exists(path_file) then
TDirectory.CreateDirectory(path_file);
try
TFile.WriteAllText(TPath.Combine(path_file, Nome_Arquivo), Arquivo_saida);
except
ShowMessage('An error occurred while saving the file.');
end;
end;
Another button:
procedure TF_corrida.BTNfinalize_appClick(Sender: TObject);
var
c: Integer;
JMediaScannerCon: Androidapi.Jni.Media.JMediaScannerConnection;
JMediaScannerCon_Client: Androidapi.Jni.Media.JMediaScannerConnection_MediaScannerConnectionClient;
begin
JMediaScannerCon:=TJMediaScannerConnection.JavaClass.init(TAndroidHelper.Context, JMediaScannerCon_Client);
JMediaScannerCon.connect;
c:=0;
while not JMediaScannerCon.isConnected do begin
Sleep(100);
inc(c);
if (c>20) then break;
end;
if (JMediaScannerCon.isConnected) then begin
JMediaScannerCon.scanFile(StringToJString(path_file), nil);
JMediaScannerCon.disconnect;
end;
end;
PS This warning had appeared:
[DCC Warning] u_corrida.pas(682): W1000 Symbol 'SharedActivityContext'
is deprecated: 'Use TAndroidHelper.Context'
So I changed the code
Note: I also tried replacing "path_file" with "System.IOUtils.TPath.GetSharedDownloadsPath", but to no avail too
This question has already been answered, the other question (index files and folders) has been moved to: How to index a created file in Android sdcard Delphi
You don't actually want "internal storage", that is private to your app and not even the user can access it (without root access to the device). You want "external storage" instead, so the user (and other apps) can access it.
Per Save files on device storage in Android's documentation:
Internal storage is best when you want to be sure that neither the user nor other apps can access your files.
External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.
Use one of the TPath.GetShared...() methods to get an "external storage" path, such as TPath.GetSharedDocumentsPath(). And make sure your app has the WRITE_EXTERNAL_STORAGE permission enabled.
Also, note that TFile.WriteAllText() will not create a missing folder (in fact, it will raise an EDirectoryNotFoundException). You have to create the folder yourself first, such as with TDirectory.CreateDirectory() or SysUtils.ForceDirectories(). TPath.Combine() simply concatenates the input strings together, it does not create the actual folder.
Try this:
procedure TF_start.Button2Click(Sender: TObject);
var
path, output_text: string;
begin
output_text := 'test';
path := TPath.Combine(TPath.GetSharedDocumentsPath, 'myfolder');
if not TDirectory.Exists(path) then
TDirectory.CreateDirectory(path);
TFile.WriteAllText(TPath.Combine(path, 'test.txt'), output_text);
end;

Parsing Memo for Files and Folders

I'm totally new to Delphi I guess learning by doing something should be ok (My hope!)
My Idea was because I often have to re-create the same tasks:
creating always the same directorys which contains sometimes files and sometimes leaved empty...
So my conclusion was to automate it in some way.
Assume a Memo containing the following:
config.xml|enc
/skin
/data/defines.dat:blub
/temp
The Basepath where all the stuff above should be created inside:
C:\users\BGates\test
":blub" is just placeholders e.g. :blub can contain any text which comes from another memo in my application which means that later defines.dat is filled with the text blub contains...
As you can see sometimes I use | and sometimes : for the placeholder...
So from the information above I would like to parse the contents of the memo to create a directory structure like this:
C:\users\BGates\test\
config.xml
skin
data
defines.dat (while defines.dat will contain the stuff which comes from blub)
temp
My problem is the parsing of the memo esspecially how to decide its a folder or its a folder in another folder, then its a file in the root or a file inside of a folder and so on...
Well it might be there is an easier way (I was reading about csv files and such but then? My tool would be hard to understand for someone using it which doesn't know how a csv file needs to look like) while my example above feels maybe familier to them...
Could someone show me please an example how to parse it in a correct (best practice) way So I could learn from it?
There are routines in the SysUtils unit that make file path parsing a lot easier. Have a look at ExtractFileName and ExtractFilePath, for starters. Also, if you're using a recent version of Delphi, (D2010 or any of the XE line,) the IOUtils unit contains a set of helper methods under the TPath record that simplify working with paths.
For example, if I wanted to deal with the line /data/defines.dat:blub, I'd do something like this:
function NormalizePath(const name: string): string;
begin
result := StringReplace(name, '/', '\', [rfReplaceAll]);
end;
procedure ProcessLine(line: string);
var
path, filename, data: string;
colonPos: integer;
begin
colonPos := pos(':', line);
if colonPos > 0 then
begin
data := copy(line, colonPos + 1);
delete(line, colonPos, MAXINT);
end;
line := TPath.Combine(BASE_PATH, normalizePath(line));
if ExtractFileExt(line) = '' then
path := line
else begin
path := ExtractFilePath(line);
filename := line;
end;
ForceDirectories(path); //ensure that the folder exists
if filename <> '' then
TFile.WriteAllText(filename, data);
end;
Note: I just wrote this off the top of my head. It may contain bugs. Don't trust it without testing it first. Also, this uses functionality from IOUtils, and things will be a little bit trickier if you don't have it in your version of Delphi. But this should give you the general idea of how to deal with the problem you're trying to solve.

Create and/or Write to a file

I feel like this should be easy, but google is totally failing me at the moment. I want to open a file, or create it if it doesn't exist, and write to it.
The following
AssignFile(logFile, 'Test.txt');
Append(logFile);
throws an error on the second line when the file doesn't exist yet, which I assume is expected. But I'm really failing at finding out how to a) test if the file exists and b) create it when needed.
FYI, working in Delphi XE.
You can use the FileExists function and then use Append if exist or Rewrite if not.
AssignFile(logFile, 'Test.txt');
if FileExists('test.txt') then
Append(logFile)
else
Rewrite(logFile);
//do your stuff
CloseFile(logFile);
Any solution that uses FileExists to choose how to open the file has a race condition. If the file's existence changes between the time you test it and the time you attempt to open the file, your program will fail. Delphi doesn't provide any way to solve that problem with its native file I/O routines.
If your Delphi version is new enough to offer it, you can use the TFile.Open with the fmOpenOrCreate open mode, which does exactly what you want; it returns a TFileStream.
Otherwise, you can use the Windows API function CreateFile to open your file instead. Set the dwCreationDisposition parameter to OPEN_ALWAYS, which tells it to create the file if it doesn't already exist.
You should be using TFileStream instead. Here's a sample that will create a file if it doesn't exist, or write to it if it does:
var
FS: TFileStream;
sOut: string;
i: Integer;
Flags: Word;
begin
Flags := fmOpenReadWrite;
if not FileExists('D:\Temp\Junkfile.txt') then
Flags := Flags or fmCreate;
FS := TFileStream.Create('D:\Temp\Junkfile.txt', Flags);
try
FS.Position := FS.Size; // Will be 0 if file created, end of text if not
sOut := 'This is test line %d'#13#10;
for i := 1 to 10 do
begin
sOut := Format(sOut, [i]);
FS.Write(sOut[1], Length(sOut) * SizeOf(Char));
end;
finally
FS.Free;
end;
end;
If you are just doing something simple, the IOUtils Unit is a lot easier. It has a lot of utilities for writing to files.
e.g.
procedure WriteAllText(const Path: string; const Contents: string);
overload; static;
Creates a new file, writes the specified string to the file, and then
closes the file. If the target file already exists, it is overwritten.
You can also use the load/save feature in a TStringList to solve your problem.
This might be a bad solution, because the whole file will be loaded into memory, modified in memory and then saved to back to disk. (As opposed to your solution where you just write directly to the file). It's obviously a bad solution for multiuser situations.
But this approach is OK for smaller files, and it is easy to work with and easy understand.
const
FileName = 'test.txt';
var
strList: TStringList;
begin
strList := TStringList.Create;
try
if FileExists(FileName) then
strList.LoadFromFile(FileName);
strList.Add('My new line');
strList.SaveToFile(FileName);
finally
strList.Free;
end;
end;

Delphi - how to get a list of all files of directory

I am working with delphi, I want a list of all files of a directory when I execute openpicturedialog.
i.e., When open dialog is executed and
i select one file from it, I want the
list of all files from the directory
of selected file.
You can even suggest me for getting directory name from FileName property of TOpenDialog
Thank You.
if you use delphi 2010 then you can use tdirectory.getfiles
first add ioutils.pas to uses clause then write the following line of code in the event handler(in addition to code you already have in that event handler)
uses IOUtils;
var
path : string;
begin
for Path in TDirectory.GetFiles(OpenPictureDialog1.filename) do
Listbox1.Items.Add(Path);{assuming OpenPictureDialog1 is the name you gave to your OpenPictureDialog control}
end;
#Himadri, the primary objective of the OpenPictureDialog is not select an directory, anyway if you are using this dialog with another purpose you can try this code.
Var
Path : String;
SR : TSearchRec;
DirList : TStrings;
begin
if OpenPictureDialog1.Execute then
begin
Path:=ExtractFileDir(OpenPictureDialog1.FileName); //Get the path of the selected file
DirList:=TStringList.Create;
try
if FindFirst(Path + '*.*', faArchive, SR) = 0 then
begin
repeat
DirList.Add(SR.Name); //Fill the list
until FindNext(SR) <> 0;
FindClose(SR);
end;
//do your stuff
finally
DirList.Free;
end;
end;
end;
Change the filter property in your OpenPictureDialog to include all files:
All (*.*)
Edit: I don't think you can select a directory in a Open(Picture)Dialog, it surely isn't the purpose of an OpenPictureDialog anyway.
Then use FindFirst and FindNext to get the files in this dir.
You can use extractFilePath function to get the directory name:
myPath := extractFilePath(FileName);
where FileName is name of file you choose by OpenDialog.
if OpenPictureDialog1.Execute then
FileListBox1.Directory := extractFilePath(OpenPictureDialog1.FileName);
You can also use a FilterComboBox linked to FileListBox to filter the file type.
TFileListBox and TFilterComboBox are in the tool palette under "Win 3.1". From Delphi 4 there are these objects.
Uses System.IOUtils;
var List : TStringlist;
var File : String := '';enter code here
var Path : string := IncludeTrailingPathDelimiter(Edit1.Text);
Lista := TStringList.Create;
try
for File in TDirectory.GetFiles(Path) do
List.Add(File); // Add all file names to list
finally
FreeAndNil(Lista);
end;

Creating Compressed (Zipped) Folder using Delphi

Can I create Windows XP's Compressed (Zipped) Folder using Delphi?
If you are using Delphi X2, just use TZipFile from System.Zip:
To Zip a folder, use:
TZipFile.ZipDirectoryContents('ZipFile.zip', 'C:\Zip\this\right\now');
To Zip files, use:
Zip := TZipFile.Create;
try
Zip.Open('ZipFile.zip', zmWrite);
Zip.Add('FileToBeZipped.txt');
Zip.Add('ThisWillBeCompressedAgainForSureAndBecomeSmaller.zip');
finally
Zip.Free;
end
According to a thread in eggheadcafe, you can use CreateFile Function with FILE_FLAG_BACKUP_SEMANTICS to create a Compressed Folder.
For shell extensions route, take a look at Using Windows XP "Compressed Folder" shell extension to work with .zip files by Namespace Edanmo, which is written in VB.
I just found the similar question asked on C++. Take a look at Creating a ZIP file on Windows (XP/2003) in C/C++. I have a feeling the easiest route is buying ZipForge. See Zip a file in Delphi code sample.
Some time ago, I've tried all of the Delphi compression libraries that I could find, and eventually I ended up using KaZip by Kiril Antonov.
My requirements were:
Free;
Open source;
Native Delphi code;
No external dependencies (dll, exe). My most important requirement;
Small memory footprint;
Easy to use;
I use it mainly to turn .kml files into .kmz, and it does that amazingly fast.
Here's an example of how I use it:
uses
KaZip;
...
// replaces a .kml file with a .kmz file
procedure KmlToKmz(const aFileName: string);
var
FS: TFileStream;
KaZip:TKaZip;
KmzFileName:TFileName;
begin
KmzFileName := ChangeFileExt(aFileName, '.kmz');
KaZip := TKaZip.Create(nil);
try
// create an empty zipfile with .kmz extension:
FS := TFileStream.Create(KmzFileName, fmOpenReadWrite or FmCreate);
try
KaZip.CreateZip(FS);
finally
FS.Free;
end;
KaZip.Open(KmzFileName); // Open the new .kmz zipfile
KaZip.Entries.AddFile(aFileName); // add the .kml
KaZip.Close;
DeleteFile(aFileName); // delete the .kml
finally
KaZip.Free;
end;
end;
Take a look at this OpenSource SynZip unit. It's even faster for decompression than the default unit shipped with Delphi, and it will generate a smaller exe (crc tables are created at startup).
No external dll is needed. Works from Delphi 6 up to XE. No problem with Unicode version of Delphi. All in a single unit.
I just made some changes to handle Unicode file names inside Zip content, not only Win-Ansi charset but any Unicode chars. Feedback is welcome.
You could use TurboPower Abbrevia which is now open source.
A "zipped" folder in Windows is nothing more than a .ZIP file compressed using any standard zip library. Compressed folders are a different animal and require an NTFS disk format.
For the "Zip" file, I strongly suggest the Turbo Power Abbrevia, which is open source and works well. You might want to check this alternate site if your using Delphi 2009 as it might be a more recent copy.
If your wanting to use the compressed folders option, you will need to modify the directory flags on the directory handle. This will only impact NEW files added to that directory and will not automatically compress existing files. If you have an existing directory you are trying to compress, then rename each existing file, and load and save it back to the original name deleting the original file when complete with each one. Yozey had a good link to the MSDN documentation. Just remember that this only works with NTFS formatted disks, so you will need to add a check for that in your code.
You can use some command line version of any compressor like 7zip and do the task using ShellExecute, or you can use a free or comercial component like anyone of these.
I had used ZipMaster and it behaves very well for my purpose. I don't know what are your size, space and performance requirements.
Take a look at these:
File Compression
FSCTL_SET_COMPRESSION
The TZipFile.ZipDirectoryContents method did not work for me, so I created my own implementation using TZipFile.add(). I am posting it here if anyone needs it.
procedure CreateZipOfDirectory(directory: string);
var
zip: TZipFile;
Arr: tarray<string>;
str: string;
function GetAllFilesInDir(const Dir: string): tarray<string>;
var
Search: TSearchRec;
procedure addAll(arr: tarray<string>; parent: string);
var
tmp: string;
begin
for tmp in arr do
begin
setlength(result, length(result) + 1);
result[length(result) - 1] := IncludeTrailingBackslash(parent) + tmp;
end;
end;
begin
setlength(result, 0);
if FindFirst(IncludeTrailingBackslash(Dir) + '*.*', faAnyFile or faDirectory, Search) = 0 then
try
repeat
if (Search.Attr and faDirectory) = 0 then
begin
setlength(result, length(result) + 1);
result[length(result) - 1] := Search.Name;
end
else if (Search.Name <> '..') and (Search.Name <> '.') then
addAll(GetAllFilesInDir(IncludeTrailingBackslash(Dir) + Search.Name), Search.Name);
until FindNext(Search) <> 0;
finally
FindClose(Search);
end;
end;
begin
Zip := TZipFile.Create;
try
Zip.Open('Foo.zip', zmWrite);
arr := GetAllFilesInDir(directory); // The Delphi TZipFile.ZipDirectoryContents does not work properly, so let's create our own.
for str in arr do
zip.Add(directory + str, str); // Add the second parameter to make sure that the file structure is preserved.
finally
zip.Free;
end;
end;

Resources