write a number into a file - pascal

I made a program to put a number in a file. But the file don't show that number(i'mean my code is working but when open the file i created he doesn't show the number.
Here is the code:
Program firstfich;
Uses Wincrt;
Type fich = file Of Integer;
Var f: fich;
x: Integer; {start }
Begin
Assign(f,'C:\a progremming works bac\first bac programe\kill.dat');
Rewrite(f);
x := 47;
Write(f,x);
Close(f);
End.

If you want to see "47" when you open the file in a text editor, you should not create a file containing the byte 47 (which is the ASCII code for the solidus character "/").
Instead, you should create a file containing the bytes 52 and 55, which are the ASCII codes for the characters "4" and "7", respectively.
You should read about how text files are represented in computer memory. See, e.g., the Wikipedia article on character encodings.
Now, to create a file containing the bytes 52 and 55, you just write the string "47" to the file (all code is in Delphi, a modern Pascal implementation -- if you are using some other Pascal implementation, you might need to modify the code slightly):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
var
f: text;
begin
try
try
AssignFile(f, 'D:\number.txt');
Rewrite(f);
Write(f, '47');
CloseFile(f);
except
on E: Exception do
Writeln(E.Message);
end;
finally
Writeln('Done.');
Readln;
end;
end.
This will create a file that contains two bytes: 52 and 55. A text editor will display the characters "4" and "7" (assuming ASCII).
On the contrary, if you would create a file that contains only the byte 47, a text editor would display the solidus character ("/", assuming ASCII).
If you want to see the actual bytes in a file, you shouldn't open it in a text editor, but in a hex editor. I encourage you to download a hex editor and play around with these concepts to learn more about them.
Update, in response to comment: If you insist on writing bytes manually, using old Pascal I/O, the following works in Delphi:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
var
b: Byte;
f: file;
begin
try
try
AssignFile(f, 'C:\Users\Andreas Rejbrand\Desktop\number.txt');
Rewrite(f, 1);
b := 52; // Or, better: Ord('4')
BlockWrite(f, b, 1);
b := 55; // Or, better: Ord('7')
BlockWrite(f, b, 1);
CloseFile(f);
except
on E: Exception do
Writeln(E.Message);
end;
finally
Writeln('Done.');
Readln;
end;
end.
Still, this is a horrible way of creating a text file containing the number "47"; it should only be considered for educational purposes. To see alternatives to old Pascal I/O, check out https://stackoverflow.com/a/58298368/282848.

program numbertofile;
var
f: TextFile;
x: Integer;
begin
assign(f, 'kill.dat');
rewrite(f);
x := 47;
write(f, x);
close(f);
end.

Just make your file a text file and your integer will be saved in the file the way you expect it to. Just set your file to a text variable like this:
Var f: text;
x: Integer; {start }
Begin
Assign(f,'C:\a progremming works bac\first bac programe\kill.dat');
Rewrite(f);
x := 47;
Write(f,x);
Close(f);
End.
note the write will not put a carriage return or linefeed after the line. if you want numbers on different lines use writeln instead of write.
Writeln(f,x);

Related

Delphi Berlin 10.1 OS X app Decode cyrillic for writing to hardDevice

I have delphi application, i need to rewrite it for OS X.
This app writes/reads data to/from HID-device.
I have issues when i'm trying to write string from mac.
Here is the line that i'm writing(from debugger on windows): 'Новый комплекс 1'
and this works good. Meanwhile if copy this from debugger to somewhere it becomes 'Íîâûé êîìïëåêñ 1'. Device shows it as it was written, in cyrillic. And that's OK.
When i'm trying to repeat this steps on OS X, device shows unreadeble symbols. But if i do hardcode 'Íîâûé êîìïëåêñ 1' from windows example it's OK again.
Give some hints.
How it on windows
Some code:
s:= 'Новый комлекс 1'
s:= AnsiToUtf8(ReplaceNull(s));
Here is ReplaceNULL:
function ReplaceNull(const Input: string): string;
var
Index: Integer;
Res: String;
begin
Res:= '';
for Index := 1 to Length(Input) do
begin
if Input[Index] = #0 then
Res:= Res + #$12
else
Res:= Res + Input[Index];
end;
ReplaceNull:= Res;
end;
this string i put to Tstringlist and then save to file:
ProgsList.SaveToFile(Mwork.pathLibs+'stream.ini', TEncoding.UTF8);
Other program read this list and then writes to device:
Progs:= TStringList.Create();
Progs.LoadFromFile(****);
s:= UTF8ToAnsi(stringreplace(Progs.Strings[i], #$12, #0, [rfReplaceAll, rfIgnoreCase]));
And then write it to device.
So the line wich writes seems like this:
"'þ5'#0'ÿ'#$11'Новый комплекс 1'#0'T45/180;55;70;85;90;95;100;T45/180'#0'ÿ'"
On the mac i succesfully get the same string. But device can't show this in cyrillic.
A Delphi string is encoded in UTF-16 on all platforms. There is no need to convert it, unless you are interacting with non-Unicode data outside of your app.
That being said, if you have a byte array that is encoded in a particular charset, you can convert it to another charset using Delphi's TEncoding.Convert() method. You can use the TEncoding.GetEncoding() method to get a TEncoding object for a particular charset (if different than the standard supported charsets - ANSI, ASCII, UTF-7, UTF-8, and UTF-16 - which have their own property getters in TEncoding).
var
SrcEnc, DstEnc: TEncoding;
SrcBytes, ConvertedBytes: TBytes;
begin
SrcBytes := ...; // Cyrillic encoded bytes
SrcEnc := TEncoding.GetEncoding('Cyrillic'); // or whatever the real name is...
try
DstEnc := TEncoding.GetEncoding('Windows-1251');
try
ConvertedBytes := TEncoding.Convert(SrcEnc, DstEnc, SrcBytes);
finally
DstEnc.Free;
end;
finally
SrcEnc.Free;
end;
// use ConvertedBytes as needed...
end;
Update: To encode a Unicode string in a particular charset, simply call the TEncoding.GetBytes() method, eg:
s := 'Новый комлекс 1';
Enc := TEncoding.GetEncoding('Windows-1251');
try
bytes := Enc.GetBytes(s);
finally
Enc.Free;
end;
s := 'Новый комлекс 1';
bytes := TEncoding.UTF8.GetBytes(s);
You can use the TEncoding.GetString() to decode bytes in a particular charset back to a String, eg:
bytes := ...; // Windows-1251 encoded bytes
Enc := TEncoding.GetEncoding('Windows-1251');
try
s := Enc.GetString(bytes);
finally
Enc.Free;
end;
bytes := ...; // UTF-8 encoded bytes
s := TEncoding.UTF8.GetString(bytes);
The answer was next. Delphi Berlin 10.1 uses KOI8-R, and my device - cp1251.
As i'd wanted to write russian symbols(Cyrillic) i've created table of matches for symbols from KOI8-R and cp1251.
So, i take string in KOI8-R make it in cp1251.
Simple code:
Dict:=TDictionary<String,String>.Create;
Dict.Add(#$439,#$E9);//'й'
Dict.Add(#$44E,#$FE);//'ю'
Dict.Add(#$430,#$E0);//'а'
....
function tkoitocp.getCP1251Code(str:string):string;
var i:integer; res,key,val:string; pair:Tpair<String,String>;
begin
res:='';
for i:=1 to length(str) do
begin
if dict.ContainsKey(str[i]) then
begin
pair:= dict.ExtractPair(str[i]);
res:=res+pair.Value;
dict.Add(pair.Key,pair.Value);
end
else
res:=res+str[i];
end;
Result:=res;
end;

Japan character encoding

I have Japanese string of 'ぱはめ'. I want to convert it into '%82%CF%82%CD%82%DF'. I hope someone will give me a function for this converting.
You need to take the string and encode it in a specific code page. Then take each encoded byte and produce its hex representation. Like this:
function MyEncode(const S: string; const CodePage: Integer): string;
var
Encoding: TEncoding;
Bytes: TBytes;
b: Byte;
sb: TStringBuilder;
begin
Encoding := TEncoding.GetEncoding(932);
try
Bytes := Encoding.GetBytes(S);
finally
Encoding.Free;
end;
sb := TStringBuilder.Create;
try
for b in Bytes do begin
sb.Append('%');
sb.Append(IntToHex(b, 2));
end;
Result := sb.ToString;
finally
sb.Free;
end;
end;
Although you have not stated this, you wish to encode the text as code page 932. So you should pass that value when calling the function.
Writeln(MyEncode('ぱはめ', 932));
I must say that in the modern day, it is somewhat surprising to see this Windows specific multi byte encoding still in use.

Reading text Files - single line vs. multiple lines

I am working on a particular scenario, where I have to read from a Text File, parse it, extract meaningful information from it, perform SQL queries with the information and then produce a reponse, output file.
I have about 3000 lines of code. Everything is working as expected. However I have been thinking of a connendrum that could possibly dissrupt my project.
The text file being read (lets call it Text.txt) may consist of a single line or multiple lines.
In my case, a 'line' is identified by its segment name - say ISA, BHT, HB, NM1, etc... each segment ending is identified by a special character '~'.
Now if the file consists of multiple lines (such that each line corresponds to a single segment); say:-
ISA....... ~
NM1....... ~
DMG....... ~
SE........ ~
and so on.... then my code essentially reads each 'line' (i.e. each segment), one at a time and stores it into a temp buffer using the following command :-
ReadLn(myFile,buffer);
and then performs evaluations based on each line. Produces the desired output. No problems.
However the issue is... what if the file consists of only a single line (consisting of multiple segments), represented as:-
ISA....... ~NM1....... ~DMG....... ~SE........ ~
then with my ReadLine command I read the entire line instead of each segment, one at a time. This doesn't work for my code.
I was thinking about creating an if, else statement pair...which is based on how many lines my Txt.txt file consists of..such as:-
if line = 1:-
then extract each segment at a time...seperated by the special character '~'
perform necessary tasks (3000 lines of code)
else if line > 1:-
then extract each line at a time (corresponding to each segment)
perform necessary tasks (3000 lines of code).
now the 3000 lines of code is repeated twice and I don't find it elegant to copy and paste all of that code twice.
I would appreciate if I could get some feedback on how to possibly solve this issue, such that, regardless of a one-line file or multiple-line file...when i proceed to evaluate, i only use one segment at a time.
There are many possible ways of doing this. Which is best for you might depend on how long these files are and how important performance is.
A simple solution is to just read characters one at a time until you hit your tilde delimiter.
The routine ReadOneItem below shows how this can be done.
procedure TForm1.Button1Click(Sender: TObject);
const
FileName = 'c:\kuiper\test2.txt';
var
MyFile : textfile;
Buffer : string;
// Read one item from text file MyFile.
// Load characters one at a time.
// Ignore CR and LF characters
// Stop reading at end-of-file, or when a '~' is read
function ReadOneItem : string;
var
C : char;
begin
Result := '';
// loop continues until break
while true do
begin
// are we at the end-of-file? If so we're done
if eof(MyFile) then
break;
// read in the next character
read ( MyFile, C );
// ignore CR and LF
if ( C = #13 ) or ( C = #10 ) then
{do nothing}
else
begin
// add the character to the end
Result := Result + C;
// if this is the delimiter then stop reading
if C = '~' then
break;
end;
end;
end;
begin
assignfile ( MyFile, FileName );
reset ( MyFile );
try
while not EOF(MyFile) do
begin
Buffer := ReadOneItem;
Memo1 . Lines . Add ( Buffer );
end;
finally
closefile ( MyFile );
end;
end;
I would use a file mapping via the Win32 API CreateFileMapping() and MapViewOfFile() functions, and then just parse the raw data as-is, scanning for ~ characters and ignoring any line breaks you might encounter in between each segment. For example:
var
hFile: THandle;
hMapping: THandle;
pView: Pointer;
FileSize, I: DWORD;
pSegmentStart, pSegmentEnd: PAnsiChar;
sSegment: AnsiString;
begin
hFile := CreateFile('Path\To\Text.txt', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile = INVALID_HANDLE_VALUE then RaiseLastOSError;
try
FileSize := GetFileSize(hFile, nil);
if FileSize = INVALID_FILE_SIZE then RaiseLastOSError;
if FileSize > 0 then
begin
hMapping := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, FileSize, nil);
if hMapping = 0 then RaiseLastOSError;
try
pView := MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, FileSize);
if pView = nil then RaiseLastOSError;
try
pSegmentStart := PAnsiChar(pView);
pSegmentEnd := pSegmentStart;
I := 0;
while I < FileSize do
begin
if pSegmentEnd^ = '~' then
begin
SetString(sSegment, pSegmentStart, Integer(pSegmentEnd-pSegmentStart));
// use sSegment as needed...
pSegmentStart := pSegmentEnd + 1;
Inc(I);
while (I < FileSize) and (pSegmentStart^ in [#13, #10]) do
begin
Inc(pSegmentStart);
Inc(I);
end;
pSegmentEnd := pSegmentStart;
end else
begin
Inc(pSegmentEnd);
Inc(I);
end;
end;
if pSegmentEnd > pSegmentStart then
begin
SetString(sSegment, pSegmentStart, Integer(pSegmentEnd-pSegmentStart));
// use sSegment as needed...
end;
finally
UnmapViewOfFile(pView);
end;
finally
CloseHandle(hMapping);
end;
end;
finally
CloseHandle(hFile);
end;

Parsing a byte file in pascal

All i need to do is parse a single bye file to read the contents to the screen but i dont know how to parse could someone please give me some rough coding i could enter file addresses in or any idea on how to parse?
this is where i currently am at
program Reordering;
uses crt;
var f, i: text;
s: string;
skyf: array [1..256] of byte;
j: integer;
result: array [1..256] of char;
begin
assign(f, 'C:\Users\Peter John Arnold\Documents\Coding\EDID1.LOG_JVC_TV_Model_LT19DK8ZJ.file');
j := 1;
Assign(i, 'C:\Users\Peter John Arnold\Documents\Coding\TV File\TvFile.txt');
rewrite(f);
reset(f);
rewrite(i);
repeat
readln(f, skyf[j]);
Result[j] := char(skyf[j]);
Append(i);
write(i, (skyf[j]));
j := j + 1;
until EOF(f);
close(f);
close(i);
s := result[1..256];
write(s);
readln();
end.
For parsing the binary file:
Read byte array from file (How to read and change a binary file)
Convert byte array obtained from file to string (every byte to
corresponding ASCII char - "chr"-function)
Use existing parsing libraries (e.g. "regexpr" unit)
Note: use "AnsiString" type

Reading integer numbers in Pascal

I'm using Pascal. I have a problem when dealing with reading file.
I have a file with integer numbers. My pascal to read the file is:
read(input, arr[i]);
if my file content is 1 2 3 then it's good but if it is 1 2 3 or 1 2 3(enter here) (there is a space or empty line at the end) then my arr will be 1 2 3 0.
From what I can recall read literally reads the file as a stream of characters, of which a blank space and carriage return are, but I believe these should be ignored as you are reading into an integer array. Does your file actually contain a space character between each number?
Another approach would be to use readLn and have the required integers stored as new lines in the file, e.g.
1
2
3
I have tested the problem on Delphi 2009 console applications. Code like this
var
F: Text;
A: array[0..99] of Integer;
I, J: Integer;
begin
Assign(F, 'test.txt');
Reset(F);
I:= -1;
while not EOF(F) do begin
Inc(I);
Read(F, A[I]);
end;
for J:= 0 to I do write(A[J], ' ');
Close(F);
writeln;
readln;
end.
works exactly as you have written. It can be improved using SeekEOLN function that skips all whitespace characters; the next code does not produce wrong additional zero:
var
F: Text;
A: array[0..99] of Integer;
I, J: Integer;
begin
Assign(F, 'test.txt');
Reset(F);
I:= -1;
while not EOF(F) do begin
if not SeekEOLN(F) then begin
Inc(I);
Read(F, A[I]);
end
else Readln(F);
end;
for J:= 0 to I do write(A[J], ' ');
Close(F);
writeln;
readln;
end.
Since all that staff is just a legacy in Delphi, I think it must work in Turbo Pascal.
You could read the string into a temporary and then trim it prior to converting it.
It doesnt hurt to mention basics like what type of Pascal on what platform you're using in order that people can give a specific answer (as the article notes, there isnt a nice way OOTB in many Pascals)
If I recall there was a string function called Val that converts a string to a number...my knowledge of Pascal is a bit rusty (Turbo Pascal v6)
var
num : integer;
str : string;
begin
str := '1234';
Val(str, num); (* This is the line I am not sure of *)
end;
Hope this helps,
Best regards,
Tom.

Resources