如何使用SysUtils.FileWrite api写入txt文件?

时间:2016-11-01 04:39:29

标签: delphi

我希望使用SysUtils.FileWrite api将我的电脑的名称写入txt文件,在我的最后一次尝试是用成功写的,但麻烦的是视觉上是剪切一些字符,但是文字的大小内部文件的大小与字符串在视觉上完整相同。

例如:我的电脑被称为" TESTE-PC" (没有双引号)。字符串" TESTE-PC" (没有双引号)恰好有8位,但SysUtils.FileWrite仅写入" TEST"文件大小为8位。很奇怪! :(

感谢您的任何建议。

uses
 Registry;

...

function GetCompName: string;
var
  Reg: TRegistry;
begin
  Reg := TRegistry.Create;
  try
    Reg.rootKey := HKEY_LOCAL_MACHINE;
    if Reg.OpenKey('SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName', false) then
    begin
      Result := Reg.ReadString('ComputerName');
      Reg.CloseKey;
    end;
  finally
    Reg.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 hFile: THandle;
 Str: PWideChar;
begin

if not fileexists('test.txt') then
begin
  Str := PWideChar(GetCompName);
  hFile:=  CreateFile('test.txt', GENERIC_WRITE, 0, nil, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
  FileWrite(hFile, Str^, Length(Str));
  CloseHandle(hFile);
end;

end;

3 个答案:

答案 0 :(得分:4)

首先,使用Registry获取计算机名称是错误的。请改用GetComputerName()功能:

uses
  Windows;

...

function GetCompName: string;
var
  CompName: array[0..MAX_COMPUTERNAME_LENGTH] of Char;
  Size: DWORD;
begin
  Size := Length(CompName);
  if GetComputerName(CompName, Size) then
    SetString(Result, CompName, Size-1)
  else
    Result := '';
end;

其次,您的FileWrite()代码失败,因为您没有正确处理字符编码。 FileWrite()仅对原始字节进行操作,但您使用的是Unicode字符串,而不考虑SizeOf(WideChar)是2,而不是像代码所假设的那样1。

您还应该使用RTL&FileCreate()功能FileWrite()。如果直接使用Win32 CreateFile()函数,您也应该直接使用Win32 API WriteFile()

无论你如何选择编写文件,都应该使用文件的绝对路径,而不是相对路径。

尝试更像这样的事情:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string
  hFile: THandle;
  Str: string;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Str := GetCompName;
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PChar(Str)^, Length(Str) * SizeOf(Char));
      FileClose(hFile);
    end;
  end;

请注意,上面的代码将以UTF-16编码创建文件。如果您想使用UTF-8,它将如下所示:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  hFile: THandle;
  Str: UTF8String;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Str := UTF8String(GetCompName);
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PAnsiChar(Str)^, Length(Str));
      FileClose(hFile);
    end;
  end;

或任何其他编码,就此而言:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  hFile: THandle;
  Enc: TEncoding;
  Str: TBytes;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Enc := TEncoding.GetEncoding('desired encoding');
    try
      Str := Enc.GetBytes(GetCompName);
    finally
      Enc.Free;
    end;
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PByte(Str)^, Length(Str));
      FileClose(hFile);
    end;
  end;

无论您决定使用哪种编码,更简单的解决方案是使用IOUtils.TFile.WriteAllText()方法:

uses
  IOUtils;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    TFile.WriteAllText(FileName, GetCompName, TEncoding.UTF8); // or TEncoding.Unicode, etc...
  end;
end;

答案 1 :(得分:0)

如果您需要编写字符,请考虑其大小:

FileWrite(hFile, Str^, Length(Str) * SizeOf(Char));

答案 2 :(得分:-1)

str的类型更改为RawByteString而不是PWideChar

procedure TForm1.FormCreate(Sender: TObject);
var
   hFile:  THandle;
   sFileName: string;
   Str: RawByteString;
begin
     Str := PWideChar(GetCompName);
     sFileName := 'Test.txt';
    if fileExists(sFileName) then
      hFile := fileOpen(sFileName,fmOpenReadWrite)
    else
      hFile := fileCreate(sFileName);
     try
       FileWrite(hFile,
        PChar(Str)^, Length(Str));
     finally
       FileClose(hFile);
     end;
end;