Insert text at top of a file

Public support forum for peer to peer support with related to the Visual Objects and Vulcan.NET products
Jamal
Posts: 315
Joined: Mon Jul 03, 2017 7:02 pm

Insert text at top of a file

Post 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
User avatar
robert
Posts: 4518
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Insert text at top of a file

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
Jamal
Posts: 315
Joined: Mon Jul 03, 2017 7:02 pm

Insert text at top of a file

Post 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

Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Insert text at top of a file

Post 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
Jamal
Posts: 315
Joined: Mon Jul 03, 2017 7:02 pm

Insert text at top of a file

Post 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
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Insert text at top of a file

Post 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
Jamal
Posts: 315
Joined: Mon Jul 03, 2017 7:02 pm

Insert text at top of a file

Post 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
User avatar
robert
Posts: 4518
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Insert text at top of a file

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
robert
Posts: 4518
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Insert text at top of a file

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

Insert text at top of a file

Post 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
Post Reply