我必须使用C#以编程方式修改文件中的文本。什么是最好的方法,避免重写整个文件内容。我只想编辑一些单词并保存。
答案 0 :(得分:2)
您可以轻松地使用StreamWriter和AppendText附加到现有文件。
如果你想做更严肃的修改,那么我认为你必须使用StreamReader将文件的内容读入C#中的内存,例如,以编程方式修改该流的内容,然后用流重写文件内容。
我认为无论如何都是这样。
答案 1 :(得分:2)
正如其他人所说,您可以轻松附加到现有文件。在文件中间插入数据需要您写出文件的其余部分。没有办法只移动文件中的所有内容。如果要覆盖单个字节,可以打开FileStream。然后使用“Seek”转到要覆盖的特定字节,并使用Write或WriteByte用新数据覆盖现有数据。
答案 2 :(得分:2)
如果您定位到Windows,则可以使用winapi CreateFile, ReadFile, WriteFile, etc。您可以轻松地写入文件中的任何位置并根据需要写入尽可能多的数据。您不必重写该文件。这甚至不需要不安全的代码。我限制了函数的功能(没有asynch或wacky文件映射)只是为了快速完成这项工作,但它可以读写文件没问题。要使此示例起作用,请创建一个100字节左右的小文本文件,并确保它位于exe的位置。这段代码中的一小部分来自MSDN网站。我已经对它做了很大的修改。
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Forms;
using Path = System.IO.Path;
class Program {
static void Main() {
string sTestFile = Path.Combine(Path.GetDirectoryName(
Application.ExecutablePath), "Test.txt");
// test reading a file
WinApiFile File = new WinApiFile(sTestFile,
WinApiFile.DesiredAccess.GENERIC_READ);
byte[] aBuffer = new byte[1000];
uint cbRead = File.Read(aBuffer, 1000);
File.Close();
// Test writing the file
File.Open(WinApiFile.DesiredAccess.GENERIC_WRITE);
// write the time to a 10 byte offset in the file
// conver the date time to byte array
int i = 0;
foreach (var ch in DateTime.Now.ToString())
aBuffer[i++] = (byte)ch;
// now write it out
File.MoveFilePointer(10); // 10 byte offset
File.Write(aBuffer, (uint)i); // write the time
File.Dispose();
}
}
public class WinApiFile : IDisposable {
/* ---------------------------------------------------------
* private members
* ------------------------------------------------------ */
private SafeFileHandle _hFile = null;
private string _sFileName = "";
private bool _fDisposed;
/* ---------------------------------------------------------
* properties
* ------------------------------------------------------ */
public bool IsOpen { get { return (_hFile != null); } }
public SafeFileHandle Handle { get { return _hFile; } }
public string FileName {
get { return _sFileName; }
set {
_sFileName = (value ?? "").Trim();
if (_sFileName.Length == 0)
CloseHandle(_hFile);
}
}
public int FileLength {
get {
return (_hFile != null) ? (int)GetFileSize(_hFile,
IntPtr.Zero) : 0;
}
set {
if (_hFile == null)
return;
MoveFilePointer(value, MoveMethod.FILE_BEGIN);
if (!SetEndOfFile(_hFile))
ThrowLastWin32Err();
}
}
/* ---------------------------------------------------------
* Constructors
* ------------------------------------------------------ */
public WinApiFile(string sFileName,
DesiredAccess fDesiredAccess) {
FileName = sFileName;
Open(fDesiredAccess);
}
public WinApiFile(string sFileName,
DesiredAccess fDesiredAccess,
CreationDisposition fCreationDisposition) {
FileName = sFileName;
Open(fDesiredAccess, fCreationDisposition);
}
/* ---------------------------------------------------------
* Open/Close
* ------------------------------------------------------ */
public void Open(
DesiredAccess fDesiredAccess) {
Open(fDesiredAccess, CreationDisposition.OPEN_EXISTING);
}
public void Open(
DesiredAccess fDesiredAccess,
CreationDisposition fCreationDisposition) {
ShareMode fShareMode;
if (fDesiredAccess == DesiredAccess.GENERIC_READ) {
fShareMode = ShareMode.FILE_SHARE_READ;
} else {
fShareMode = ShareMode.FILE_SHARE_NONE;
}
Open(fDesiredAccess, fShareMode, fCreationDisposition, 0);
}
public void Open(
DesiredAccess fDesiredAccess,
ShareMode fShareMode,
CreationDisposition fCreationDisposition,
FlagsAndAttributes fFlagsAndAttributes) {
if (_sFileName.Length == 0)
throw new ArgumentNullException("FileName");
_hFile = CreateFile(_sFileName, fDesiredAccess, fShareMode,
IntPtr.Zero, fCreationDisposition, fFlagsAndAttributes,
IntPtr.Zero);
if (_hFile.IsInvalid) {
_hFile = null;
ThrowLastWin32Err();
}
_fDisposed = false;
}
public void Close() {
if (_hFile == null)
return;
_hFile.Close();
_hFile = null;
_fDisposed = true;
}
/* ---------------------------------------------------------
* Move file pointer
* ------------------------------------------------------ */
public void MoveFilePointer(int cbToMove) {
MoveFilePointer(cbToMove, MoveMethod.FILE_CURRENT);
}
public void MoveFilePointer(int cbToMove,
MoveMethod fMoveMethod) {
if (_hFile != null)
if (SetFilePointer(_hFile, cbToMove, IntPtr.Zero,
fMoveMethod) == INVALID_SET_FILE_POINTER)
ThrowLastWin32Err();
}
public int FilePointer {
get {
return (_hFile != null) ? (int)SetFilePointer(_hFile, 0,
IntPtr.Zero, MoveMethod.FILE_CURRENT) : 0;
}
set {
MoveFilePointer(value);
}
}
/* ---------------------------------------------------------
* Read and Write
* ------------------------------------------------------ */
public uint Read(byte[] buffer, uint cbToRead) {
// returns bytes read
uint cbThatWereRead = 0;
if (!ReadFile(_hFile, buffer, cbToRead,
ref cbThatWereRead, IntPtr.Zero))
ThrowLastWin32Err();
return cbThatWereRead;
}
public uint Write(byte[] buffer, uint cbToWrite) {
// returns bytes read
uint cbThatWereWritten = 0;
if (!WriteFile(_hFile, buffer, cbToWrite,
ref cbThatWereWritten, IntPtr.Zero))
ThrowLastWin32Err();
return cbThatWereWritten;
}
/* ---------------------------------------------------------
* IDisposable Interface
* ------------------------------------------------------ */
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool fDisposing) {
if (!_fDisposed) {
if (fDisposing) {
if (_hFile != null)
_hFile.Dispose();
_fDisposed = true;
}
}
}
~WinApiFile() {
Dispose(false);
}
/* ---------------------------------------------------------
* WINAPI STUFF
* ------------------------------------------------------ */
private void ThrowLastWin32Err() {
Marshal.ThrowExceptionForHR(
Marshal.GetHRForLastWin32Error());
}
[Flags]
public enum DesiredAccess : uint {
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000
}
[Flags]
public enum ShareMode : uint {
FILE_SHARE_NONE = 0x0,
FILE_SHARE_READ = 0x1,
FILE_SHARE_WRITE = 0x2,
FILE_SHARE_DELETE = 0x4,
}
public enum MoveMethod : uint {
FILE_BEGIN = 0,
FILE_CURRENT = 1,
FILE_END = 2
}
public enum CreationDisposition : uint {
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXSTING = 5
}
[Flags]
public enum FlagsAndAttributes : uint {
FILE_ATTRIBUTES_ARCHIVE = 0x20,
FILE_ATTRIBUTE_HIDDEN = 0x2,
FILE_ATTRIBUTE_NORMAL = 0x80,
FILE_ATTRIBUTE_OFFLINE = 0x1000,
FILE_ATTRIBUTE_READONLY = 0x1,
FILE_ATTRIBUTE_SYSTEM = 0x4,
FILE_ATTRIBUTE_TEMPORARY = 0x100,
FILE_FLAG_WRITE_THROUGH = 0x80000000,
FILE_FLAG_OVERLAPPED = 0x40000000,
FILE_FLAG_NO_BUFFERING = 0x20000000,
FILE_FLAG_RANDOM_ACCESS = 0x10000000,
FILE_FLAG_SEQUENTIAL_SCAN = 0x8000000,
FILE_FLAG_DELETE_ON = 0x4000000,
FILE_FLAG_POSIX_SEMANTICS = 0x1000000,
FILE_FLAG_OPEN_REPARSE_POINT = 0x200000,
FILE_FLAG_OPEN_NO_CALL = 0x100000
}
public const uint INVALID_HANDLE_VALUE = 0xFFFFFFFF;
public const uint INVALID_SET_FILE_POINTER = 0xFFFFFFFF;
// Use interop to call the CreateFile function.
// For more information about CreateFile,
// see the unmanaged MSDN reference library.
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
DesiredAccess dwDesiredAccess,
ShareMode dwShareMode,
IntPtr lpSecurityAttributes,
CreationDisposition dwCreationDisposition,
FlagsAndAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal static extern Int32 CloseHandle(
SafeFileHandle hObject);
[DllImport("kernel32", SetLastError = true)]
internal static extern bool ReadFile(
SafeFileHandle hFile,
Byte[] aBuffer,
UInt32 cbToRead,
ref UInt32 cbThatWereRead,
IntPtr pOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool WriteFile(
SafeFileHandle hFile,
Byte[] aBuffer,
UInt32 cbToWrite,
ref UInt32 cbThatWereWritten,
IntPtr pOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern UInt32 SetFilePointer(
SafeFileHandle hFile,
Int32 cbDistanceToMove,
IntPtr pDistanceToMoveHigh,
MoveMethod fMoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetEndOfFile(
SafeFileHandle hFile);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern UInt32 GetFileSize(
SafeFileHandle hFile,
IntPtr pFileSizeHigh);
}
答案 3 :(得分:1)
当您打开文件进行书写时,只有两种可能的结果。你可以打开它进行追加,只允许你在最后写,或者打开它进行正常写入,在这种情况下你将从文件的开头写。没有“在中点打开,写入然后根据插入长度移动剩余内容”。
某些API可能允许进行此类修改但在幕后,它们只允许您进行这两项基本操作。您不必担心重写整个文件,但是,除非您的文件很大且硬盘驱动器速度很慢,否则操作不是很糟糕。你应该更多地担心你这样做的次数。
答案 4 :(得分:0)
读取文件并修改它然后再读出来可能更简单。
为了真正高效(即不为每个操作读取/写入整个文件),您需要做一些内容保存以跟踪文件的元数据,然后进行二进制编辑。
您仍然需要管理文件增长并需要追加的情况等等。