Page 1 of 2
Insert text at top of a file
Posted: Fri Dec 28, 2018 8:57 pm
by Jamal
Hello,
I am trying to add fields names to top of a CSV file. The issue is that the newly added line overwrites the first line in the passed text file. How to avoid the issue by moving first line down and inserting the new line.
BTW, I am using DBServer:CopyDelimited() to create the CSV file.
Code: Select all
function AddFieldsHeaders(cFileName as string, cDelim as string, aListBoxItems as array) as void pascal
local ptrHandle as ptr
LOCAL I as DWORD
LOCAL dwFieldsCount := ALen(aListBoxItems) as DWORD
IF (ptrHandle := FOpen2(cFileName, FO_READWRITE)) != F_ERROR
// Reset file position to beginning-of-file
FSeek(ptrHandle, 0)
FOR I := 1 upto dwFieldsCount
FWrite(ptrHandle, cDelim + aListBoxItems[I] + cDelim + iif( I < dwFieldsCount, ",",""))
next
FWrite(ptrHandle, CRLF)
FClose(ptrHandle)
ENDIF
return
Any hints appreciated.
Happy New Year!
Jamal
Insert text at top of a file
Posted: Fri Dec 28, 2018 9:18 pm
by robert
Jamal,
There is no FInsert().
In VO and Vulcan with the F..() functions:
- Create a new file with a new name
- Write the header line
- Write the whole original file
- Close the new file
- Delete the original file
- Rename the new file to the original file.
or if you don't want to work with 2 files:
- Open the file Read/Write
- Read the whole buffer in a variable (string or allocated memory)
- FSeek() to begin of file
- Fwrite the header line
- Fwrite the copy of the buffer that you saved in the variable
- Close the file.
Robert
Insert text at top of a file
Posted: Fri Dec 28, 2018 9:36 pm
by Jamal
Robert,
I used the 2 files method and it worked fine.
Thanks!
Jamal
Edit:
I decided finally it's probably more efficient and faster to use only one file, so here is the code if anyone find it useful:
Code: Select all
function AddFieldsHeaders(cFileName as string, cDelim as string, aListBoxItems as array) as void pascal
local cFileContents as string
local pInFile as ptr
LOCAL I as DWORD
LOCAL dwFieldsCount := ALen(aListBoxItems) as DWORD
cFileContents := LoadFileContents(cFileName) // this calls a C# method. MemoRead() can be used, but found it unreliable in some situations.
IF (pInFile := FOpen2(cFileName, FO_READWRITE)) != F_ERROR
FOR I := 1 upto dwFieldsCount
FWrite(pInFile, cDelim + aListBoxItems[I] + cDelim + iif( I < dwFieldsCount, ",",_chr(13)))
next
FWrite(pInFile, cFileContents)
FClose(pInFile)
ENDIF
RETURN
Insert text at top of a file
Posted: Sat Dec 29, 2018 5:23 pm
by Karl-Heinz
Hi Robert and Chris,
Because Jamal has mentioned Memoread(), i´ve looked at what memoread() and memowrit() are currently doing.
i have a OEM textfile with this content:
Das ist ein Test
mit den Umlauten Ž™š„”
und auch mit á
The correctly converted content looks like:
Das ist ein Test
mit den Umlauten ÄÖÜäöü
und auch mit ß
1.) VO behaviour
According the VO-Help MemoRead() and MemWrit() make a automatic conversion, if setAnsi() is set to false.
While MemoWrit() respects the SetAnsi() setting, MemoRead() ignores it. So, reading the OEM-File
requires a Oem2Ansi() .
Code: Select all
SetAnsi ( FALSE )
c := Oem2Ansi(MemoRead ( "D:testoemtest1.txt") )
// because setansi(.f.) is still active , oemtest2.txt
// has the same Oem content as oemtest1.txt
MemoWrit ( "D:testoemtest2.txt" , c )
2). X# behaviour
MemoRead() uses System.IO.File.ReadAllText() and Memowrit() System.IO.File.WriteAllText(), but no encoding is used. So i think something like this is required:
Code: Select all
FUNCTION MemoWrit(cFile AS STRING,c AS STRING) AS LOGIC
LOCAL lOk AS LOGIC
...
IF SetAnsi() // <------
System.IO.File.WriteAllText(cFile, c)
ELSE
System.IO.File.WriteAllText(cFile, c , System.Text.Encoding.GetEncoding(RuntimeState:DosCodepage)) // <----
ENDIF
...
RETURN lOk
FUNCTION MemoRead(cFile AS STRING) AS STRING
LOCAL cResult AS STRING
...
IF SetAnsi() // <------
cResult := System.IO.File.ReadAllText(cFile)
ELSE
cResult := System.IO.File.ReadAllText(cFile,System.Text.Encoding.GetEncoding(RuntimeState:DosCodepage) ) // <-----
ENDIF
...
RETURN cResult
regards
Karl-Heinz
Insert text at top of a file
Posted: Sat Dec 29, 2018 7:45 pm
by Jamal
Karl,
Here is my C# function to read a text file using FileStream and StreamReader which uses Encoding.Default.
public string ReadTextFile(string sFile)
{
string text = "";
var fileStream = new FileStream(@sFile, FileMode.Open, FileAccess.Read);
using (var streamReader = new StreamReader(fileStream, Encoding.Default))
{
text = streamReader.ReadToEnd();
}
return text;
}
Jamal
Insert text at top of a file
Posted: Sun Dec 30, 2018 9:53 am
by Karl-Heinz
Hi Jamal,
the problem is your "Encoding.Default" usage. With your func i have no chance to get a correct conversion. To see
my "umlaute" with your func i would need - if setansi() is set to false - a RuntimeState:DosCodepage encoding. Here this codepage is 850. So when i change your code to:
StreamReader { fileStream, System.Text.Encoding.GetEncoding(850) }
is see my "umlaute" correctly.
regards
Karl-Heinz
Insert text at top of a file
Posted: Sun Dec 30, 2018 4:49 pm
by Jamal
Hi Karl,
I am in the US so I do not have to use "umlautes", however, in my case I was creating HTML files and when I used MemoRead(), it always inserted  at the beginning of the first line and thus I had to resort to .NET to fix the issue. I assume that MemoRead is actually using Win32 ReadFile() function because it exhibited the same behavior.
Jamal
Insert text at top of a file
Posted: Mon Dec 31, 2018 11:29 am
by robert
Jamal,
MemoRead in the X# runtime uses managed file functions to load the text.
You can see the source for this function in our Git Repo:
https://github.com/X-Sharp/XSharpPublic ... o.prg#L373
Since we are not passing an encoding then the .net runtime will try to determinge the file format. This usually works quite well.
See
https://docs.microsoft.com/en-us/dotnet ... em_String_ for more info about what the function in the .Net runtime does.
I have no idea why you see extra characters in your string, I would need to know the active codepage on your machine and would have to see the contents of the file.
Robert
Insert text at top of a file
Posted: Mon Dec 31, 2018 11:40 am
by robert
I did a quick check with IlSpy and Vulcan uses FOpen() and FREad() to read the file inside MemoRead() and then translates the files from bytes to unicode with Mem2String().
Robert
Insert text at top of a file
Posted: Mon Dec 31, 2018 1:01 pm
by Karl-Heinz
robert wrote:I did a quick check with IlSpy and Vulcan uses FOpen() and FREad() to read the file inside MemoRead() and then translates the files from bytes to unicode with Mem2String().
Robert
Hi Robert,
I just tried it. VOs memoread() and memowrit() do a binary read/write
LOCAL c AS STRING
c := MemoRead ( "d:testAZG232849601_002_20181228.pdf")
? MemoWrit ( "d:testmemowrite.pdf" , c )
never did something like this with VO before, but the created memowrite.pdf has exactly the same size and can be opened by a pdf viewer without problems. This is of course not possible with currently used System.IO.File.WriteAllText() and System.IO.File.ReadAllText() .
regards
Karl-Heinz