代码之家  ›  专栏  ›  技术社区  ›  Gulzar Nazim

如何使用c向文件插入字符#

  •  13
  • Gulzar Nazim  · 技术社区  · 17 年前

    我有一个巨大的文件,我必须在特定位置插入某些字符。在C语言中,在不重写整个文件的情况下,最简单的方法是什么?

    10 回复  |  直到 17 年前
        1
  •  10
  •   bineteri    17 年前

    文件系统不支持在文件中间“插入”数据。如果您真的需要一个可以以排序方式写入的文件,我建议您研究使用嵌入式数据库。

    你可能想看看 SQLite BerkeleyDB .

    然后,您可能正在使用文本文件或旧的二进制文件。在这种情况下,您唯一的选择是重写文件,至少从插入点到结尾。

    我会看看 FileStream 类在C中执行随机I/O。

        2
  •  3
  •   Mike Thompson    17 年前

    您可能需要重写从插入更改到结尾的文件。您最好总是将数据写到文件的末尾,并使用诸如sort和grep之类的工具以所需的顺序将数据取出。我假设您在这里谈论的是文本文件,而不是二进制文件。

        3
  •  2
  •   Socratees    17 年前

    如果不重写字符,就无法在文件中插入字符。使用C它可以用任何流类来完成。如果文件很大,我建议您在C代码中使用GNU核心实用程序。他们是最快的。我曾经使用核心实用程序(大小为4GB、8GB或更多等)处理非常大的文本文件。像head、tail、split、csplit、cat、shuf、shred、uniq这样的命令在文本操作中帮助很大。

    例如,如果您需要在一个2GB文件中放置一些字符,您可以使用split-b字节数,将ouptut放入一个文件,将新文本附加到该文件中,然后获取其余内容并添加到该文件中。这应该比任何其他方法都快。

    希望它能起作用。试一试。

        4
  •  1
  •   FlySwat    17 年前

    您可以使用随机访问来写入文件的特定位置,但是您将无法以文本格式进行写入,您必须直接使用字节。

        5
  •  1
  •   Scott Marlowe    17 年前

    如果知道要写入新数据的特定位置,请使用BinaryWriter类:

    using (BinaryWriter bw = new BinaryWriter (File.Open (strFile, FileMode.Open)))
    {
        string strNewData = "this is some new data";
        byte[] byteNewData = new byte[strNewData.Length];
    
        // copy contents of string to byte array
        for (var i = 0; i < strNewData.Length; i++)
        {
            byteNewData[i] = Convert.ToByte (strNewData[i]);
        }
    
        // write new data to file
        bw.Seek (15, SeekOrigin.Begin);  // seek to position 15
        bw.Write (byteNewData, 0, byteNewData.Length);
    }
    
        6
  •  1
  •   Fabrizio Stellato    10 年前

    你可以看看这个项目: Win Data Inspector

    基本上,代码如下:

    // this.Stream is the stream in which you insert data
    
    {
    
    long position = this.Stream.Position;
    
    long length = this.Stream.Length;
    
    MemoryStream ms = new MemoryStream();
    
    this.Stream.Position = 0;
    
    DIUtils.CopyStream(this.Stream, ms, position, progressCallback);
    
    ms.Write(data, 0, data.Length);
    
    this.Stream.Position = position;
    
    DIUtils.CopyStream(this.Stream, ms, this.Stream.Length - position, progressCallback);
    
    this.Stream = ms;
    
    }
    
    #region Delegates
    
    public delegate void ProgressCallback(long position, long total);
    
    #endregion
    

    二恶英

    public static void CopyStream(Stream input, Stream output, long length, DataInspector.ProgressCallback callback)
    {
        long totalsize = input.Length;
        long byteswritten = 0;
        const int size = 32768;
        byte[] buffer = new byte[size];
        int read;
        int readlen = length < size ? (int)length : size;
        while (length > 0 && (read = input.Read(buffer, 0, readlen)) > 0)
        {
            output.Write(buffer, 0, read);
            byteswritten += read;
            length -= read;
            readlen = length < size ? (int)length : size;
            if (callback != null)
                callback(byteswritten, totalsize);
        }
    }
    
        7
  •  0
  •   Sev    17 年前

    根据项目的范围,您可能需要决定将文件中的每一行文本插入到 表数据结构。有点像数据库表 ,这样您就可以在任何给定时刻插入到特定位置,而不必每次都读取、修改和输出整个文本文件。这是因为你的数据是“巨大的”,正如你所说的。您仍然可以重新创建该文件,但至少可以用这种方式创建一个可扩展的解决方案。

        8
  •  0
  •   Captain Segfault    17 年前

    这可能是“可能的”,这取决于文件系统如何存储文件,以便在中间快速插入(即,添加额外的)字节。如果可以远程执行,那么一次只能执行一个完整的块,并且只能通过对文件系统本身进行低级修改或使用特定于文件系统的接口来实现。

    文件系统通常不是为此操作设计的。如果需要快速执行插入操作,则需要更通用的数据库。

    根据您的应用程序的不同,中间的一点是将插入组合在一起,因此您只需重写一次文件,而不是20次。

        9
  •  0
  •   user1088520    14 年前

    您总是需要重写插入点的剩余字节。如果这一点是0,那么您将重写整个文件。如果它比最后一个字节早10个字节,那么您将重写最后10个字节。

    在任何情况下,都没有直接支持“插入到文件”的功能。但是下面的代码可以准确地完成。

    var sw = new Stopwatch();
    var ab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";
    
    // create
    var fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
    sw.Restart();
    fs.Seek(0, SeekOrigin.Begin);
    for (var i = 0; i < 40000000; i++) fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
    sw.Stop();
    Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);
    fs.Dispose();
    
    // insert
    fs = new FileStream(@"d:\test.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite, 262144, FileOptions.None);
    sw.Restart();
    byte[] b = new byte[262144];
    long target = 10, offset = fs.Length - b.Length;
    while (offset != 0)
    {
        if (offset < 0)
        {
            offset = b.Length - target;
            b = new byte[offset];
        }
        fs.Position = offset; fs.Read(b, 0, b.Length);
        fs.Position = offset + target; fs.Write(b, 0, b.Length);
        offset -= b.Length;
    }
    fs.Position = target; fs.Write(ASCIIEncoding.ASCII.GetBytes(ab), 0, ab.Length);
    sw.Stop();
    Console.WriteLine("{0} ms", sw.Elapsed.TotalMilliseconds);
    

    为了获得更好的文件IO性能,可以像上面的代码一样使用“神奇的两个数字”。文件的创建使用了262144字节(256KB)的缓冲区,这一点都没有帮助。用于插入的缓冲区执行“性能作业”,正如运行代码时秒表结果所示。在我的电脑上进行的草稿测试给出了以下结果:

    创建13628.8 ms,插入3597.0971 ms。

    注意,插入的目标字节是10,这意味着几乎整个文件都被重写了。

        10
  •  0
  •   donaastor    9 年前

    为什么不把一个指针放在文件的末尾(字面意思是,比当前文件大四个字节),然后在文件的末尾写下插入数据的长度,最后写下要插入的数据本身。例如,如果文件中间有一个字符串,并且希望在字符串中间插入几个字符,则可以在字符串中的大约四个字符上写一个指向文件结尾的指针,然后将这四个字符连同您首先要插入的字符一起写到末尾。一切都是为了订购数据。当然,只有当您自己编写整个文件时,您才能这样做,我的意思是您没有使用其他编解码器。

    推荐文章