u012081782
aiaify
采纳率100%
2020-04-25 17:56

如何对单个二进制文件中指定位置的流进行替换或者删除?

300
已采纳

限制条件:
1.不能把整个文件所有内容直接读取到内存后拼接重组(文件较大)
2.替换内容长度大于被替换内容

目标示例:
如文件原内容为**12356**,现在要将position位置为4的'3'替换为'34'使最终结果为**123456**,或者删除'3'使最终结果为**1256**。

注:
1.* 意为任意的二进制值
2.希望获取C++或者C#的解决方法代码,有明确解决思路亦可

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

3条回答

  • caozhy 回答这么多问题就耍赖把我的积分一笔勾销了 1年前

    如果替换内容长度>或者<原来的长度。那么,无论你用什么语言,用什么算法,最优化的情况,需要把修改点到文件结尾的文件重新覆盖重写一遍。
    因为文件是连续存储在磁盘上的。
    如果你可以自己定义文件的格式(也就是说你的文件只由你的程序读取,而不是被别的程序读取),你可以考虑使用链式存储或者稀疏存储,使得替换内容的操作变得高效(代价是浪费一部分存储)
    先把原则和你说清楚。
    如果你需要写程序,可以写给你。

    代码还有一些问题,正在改

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    namespace Q1065402
    {
        class MyLinkedFile : IDisposable
        {
            private const int EOF = -1;
            private const int BOF = 0;
            private FileStream fs = null;
            private string filename;
            private int curr = 0;
    
            private byte[] MakeBytes(int pre, int next, int value)
            {
                return BitConverter.GetBytes(pre).Concat(BitConverter.GetBytes(next)).Concat(BitConverter.GetBytes(value)).ToArray();
            }
            private void parseBytes(byte[] arr, out int pre, out int next, out int value)
            {
                pre = BitConverter.ToInt32(arr, 0);
                next = BitConverter.ToInt32(arr, 4);
                value = BitConverter.ToInt32(arr, 8);
            }
    
            public MyLinkedFile(string fn)
            {
                if (!File.Exists(fn))
                    File.WriteAllBytes(fn, MakeBytes(BOF, EOF, 0));
                fs = new FileStream(fn, FileMode.OpenOrCreate);
                filename = fn;
            }
    
            public IEnumerable<int> ReadAll()
            {
                int pre = 0;
                int next = 0;
                int value = 0;
                curr = -1;
                fs.Position = 0;
                byte[] data = new byte[12];
                fs.Read(data, 0, 12);
                parseBytes(data, out pre, out next, out value);
                while (true)
                {
                    if (next == EOF) break;
                    curr++;
                    fs.Position = next * 12;
                    fs.Read(data, 0, 12);
                    parseBytes(data, out pre, out next, out value);
                    yield return value;
                }
            }
    
            private void moveToBegin()
            {
                foreach (var item in ReadAll().Take(1)) ;
            }
    
            public void moveToEnd()
            {
                foreach (var item in ReadAll());
            }
    
            public void Append(int val)
            {
                int pre = 0;
                int next = 0;
                int value = 0;
                byte[] data = new byte[12];
                fs.Read(data, 0, 12);
                parseBytes(data, out pre, out next, out value);
                fs.Position -= 12;
                fs.Write(MakeBytes(pre, (int)(fs.Length / 12), value), 0, 12);
                pre = (int)fs.Position / 12;
                fs.Position = fs.Length;
                fs.SetLength(fs.Length + 12);
                fs.Write(MakeBytes(pre, next, val), 0, 12);
                curr++;
            }
    
            public void Dispose()
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                    fs = null;
                    filename = "";
                }
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                using (MyLinkedFile lf = new MyLinkedFile(@"c:\1.bin"))
                {
                    lf.moveToEnd();
                    lf.Append(21);
                    lf.Append(22);
                    lf.Append(23);
                    //foreach (var item in lf.ReadAll())
                    //    Console.WriteLine(item);
                }
            }
        }
    }
    
    
    点赞 2 评论 复制链接分享
  • hxycsdn9159 hxycsdn9159 1年前

    感觉没有那么麻烦,给你提供个思路:比如你的大文件是A,然后你可以先创建一个文件B,然后用文件指针循环每次读取A文件的部分内容,检测读取到的内容中是不是有需要你替换的,如果有就替换一下,没有就不用处理,然后把这部分内容Append到B文件,就这样依次循环到A文件的EOF结束然后B文件就是你需要的新文件,至于每次读取多少内容耗多少内存你自己可以控制,这样再大的文件也能处理,从你的描述感觉你只是想修改一个大文件而且怕内存一下装不下这个文件而已,链式存储和稀疏存储的话你可以参考下很多大的压缩包文件会分好几个卷存储,但是读取这些文件解压的时候必须由相应的程序去处理,其实原理也就是前面的一卷数据文件里面包含后面一卷数据的指针罢了,就像个链表的存储结构一样,前面一个结构体包含下个结构体的指针,感觉你根本用不到。

    点赞 评论 复制链接分享
  • phenix2009 白色一大坨 1年前

    单个文件做不到,文件是连续存储的,除非你拆成多个文件来保存,这样在哪项出了问题需要修改时候,涉及的数据量会小一些。

    点赞 评论 复制链接分享