如何实现文件输出重定向

zjcxc 2018-01-30 10:34:47
有一个现成的工具,会把大量数据写入一个明确的文件,是否可以拦截文件的写入数据,对这些数据进行自定义的处理,比如压缩,写到多个文件等
网上找到一些信息,似乎可以用 HOOK(钩子)技术实现,但网上搜索上到的都是键盘、鼠标的例子,没有针对文件写入的
不知道大家有什么方法可以实现这个需求
...全文
791 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
你 #27 的代码不可能行的 1、你不知道原始文件何时发生了变化 2、你不知道原始文件发生了多少变化 3、你没打算对已处理过的内容区别对待
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
嗯,侦听打开流时加个 FileShare.ReadWrite 一切ok
zjcxc 2018-02-02
  • 打赏
  • 举报
回复
搞不定,不知道什么原因,写入副本的数据明显不对
Module Module1
    ' 测试输出文件, 这个名称后面加 .copy 是测试输出文件的副本(由 Read 过程写入)
    Private _File As String = "f:\temp\test.txt"
    Private _Work As Boolean = False

    Sub Main()
        ' 删除测试文件
        If IO.File.Exists(_File) Then IO.File.Delete(_File)
        ' 通过线程启动工具输出文件的坊和写入副本
        Dim iThread As New Threading.Thread(AddressOf Read)
        iThread.Start()
        ' 启动 BCP 工具做文件导出
        Using ps As New Process
            With ps.StartInfo
                .UseShellExecute = False
                .FileName = "bcp"
                .Arguments = """select top (1000) O.* from sys.all_objects O, sys.all_objects O1"" queryout f:\temp\test.txt -T -N"
            End With
            Console.WriteLine("Process Enger key to start")
            Console.ReadLine()
            _Work = True
            If ps.Start() Then ps.WaitForExit()
            ps.Close()
            _Work = False
        End Using

        Console.WriteLine("Done !!! Process Enger key to Exit")
        Console.ReadLine()
    End Sub

    Sub Read()
        ' 等待工作开始
        While _Work = False
            Threading.Thread.Sleep(1)
        End While
        ' 等待文件就绪
        While IO.File.Exists(_File) = False
            Threading.Thread.Sleep(1)
        End While

        ' 文件读写 buffer
        Dim BufferSize = 1024 * 4
        Dim Buffer(BufferSize) As Char

        '工具写入文件的同步副本
        Dim FileW = _File & ".copy"
        If IO.File.Exists(FileW) Then IO.File.Delete(FileW)
        Using fw As New IO.StreamWriter(FileW)
            fw.AutoFlush = True
            ' 读取工具写入文件,并写入副本
            Using fs As New IO.FileStream(_File, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.ReadWrite)
                Using fr As New IO.StreamReader(fs)
                    Dim ReadCount As Integer = 0
                    ' 工具工作中的持续读取
                    While _Work
                        ReadCount = fr.ReadBlock(Buffer, 0, BufferSize)
                        If ReadCount > 0 Then fw.Write(Buffer, 0, ReadCount)
                    End While
                    ' 工具完成后的剩余数据读取
                    While True
                        ReadCount = fr.ReadBlock(Buffer, 0, BufferSize)
                        If ReadCount = 0 Then Exit While
                        fw.Write(Buffer, 0, ReadCount)
                    End While
                    fr.Close()
                End Using
                fs.Close()
            End Using
            fw.Close()
        End Using
    End Sub
End Module
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
大致这样
namespace 数据源
{
    class Program
    {
        static void Main(string[] args)
        {
            var filename = "1.txt";
            Task.Factory.StartNew(() =>
            {
                int n = 0;
                while (true)
                {
                    for (var i = 0; i < 10000; i++)
                    {
                        var s = new string[] { n + "-" + i.ToString() };
                        if (i == 0) File.WriteAllLines(filename, s);
                        else File.AppendAllLines(filename, s);
                        Console.WriteLine(s[0]);
                    }
                    n++;
                }
            });
            Console.ReadKey();

        }
    }
}
namespace 侦听
{
    class Program
    {
        static string filename = "1.txt";
        static long last = 0;
        static void Main(string[] args)
        {
            Console.WriteLine(System.IO.Directory.GetCurrentDirectory());
            var watcher = new FileSystemWatcher();
            watcher.Path = System.IO.Directory.GetCurrentDirectory();
            watcher.Filter = filename;
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;
            Console.ReadKey();
        }
        private static void OnChanged(object source, FileSystemEventArgs e)
        {
            string s = "";
            FileStream fs = null;
            do
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                }
                catch (System.IO.IOException) { }

            } while (fs == null);
            fs.Position = fs.Length > last ? last : 0;
            var sr = new StreamReader(fs);
            s = sr.ReadToEnd();
            last = fs.Position;
            sr.Close();
            fs.Close();
            sr.Dispose();
            fs.Dispose();

            Console.WriteLine(s);
        }
    }
}
不过 数据源 程序会出现自动终止(没有监听时不会)可能是写文件时出现了共享错误,但并没有报错 可见此方案还是存在风险的,因为你无法保证人家就不使用最简单的方式写日志
zjcxc 2018-02-02
  • 打赏
  • 举报
回复
我的方法是可行的,把 StreamReader/Writer 改成 BinaryReader/Writer 就正常了 这算免费解决了一些问题吧 没有 HOOK 完美,如果能研究清楚 HOOK 的话,应该能完美重定向读和写,目前这种只能把别人的写再抛出来,也不是真正的重定向 当然, HOOK 也只是传说中的技术,毕竟没研究出来
  • 打赏
  • 举报
回复
引用 34 楼 zjcxc 的回复:
[quote=引用 32 楼 xuzuning 的回复:] 人家还没写,或只写了一半,你自然是得不到全部的, 所以,慢一拍是正常的。除非你能重定向
不是慢一怕,是要人家写完,我用 sql server 的 bcp 做的测试,你那个监控的实例,只会触发一次,并且是在 BCP 导出完成的时候,这样达不到效果,我想实现的是 BCP 导出过程中就对数据估处理(管道效果,重点是管道效果) 我要的是增量读取,也就是我读的时候,你写了多少,我读多少,下次我读的时候,你在我上次读了的基础上写了多少,我再读多少 所以你看我写的,是人家工具开始之前我就开始了,一直狂读,直返人家的工具完成了,我也完成了,只是读到的数据似乎不对 [/quote] 记录读取的位置,下次从该位置开始读取,比较文件大小是否大于读取位置。
zjcxc 2018-02-02
  • 打赏
  • 举报
回复
引用 32 楼 xuzuning 的回复:
人家还没写,或只写了一半,你自然是得不到全部的, 所以,慢一拍是正常的。除非你能重定向
不是慢一怕,是要人家写完,我用 sql server 的 bcp 做的测试,你那个监控的实例,只会触发一次,并且是在 BCP 导出完成的时候,这样达不到效果,我想实现的是 BCP 导出过程中就对数据估处理(管道效果,重点是管道效果) 我要的是增量读取,也就是我读的时候,你写了多少,我读多少,下次我读的时候,你在我上次读了的基础上写了多少,我再读多少 所以你看我写的,是人家工具开始之前我就开始了,一直狂读,直返人家的工具完成了,我也完成了,只是读到的数据似乎不对
zjcxc 2018-02-02
  • 打赏
  • 举报
回复
另外,我就是想知道有可能的实现方法,跟项目进度没关系,我又不是做项目,求解而已
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
项目卡壳了,只能有两种解决办法: 1、搁置项目,直到直到找到解决问题的办法 2、调整需求,继续按新的方案进行(退而求其次) 你说哪样更务实呢?
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
人家还没写,或只写了一半,你自然是得不到全部的, 所以,慢一拍是正常的。除非你能重定向
xuzuning 2018-02-02
  • 打赏
  • 举报
回复
打开的流是不会随原始文件的变化而变化的,所以打开时刻之后的变化需要下次打开才能得到
zjcxc 2018-02-02
  • 打赏
  • 举报
回复
侦听达不到要求,我测试了一下,侦听的方式,要工具写数据完成,才触发事件,这个时候已经没有意义了,我想要的是数据写入的同时读出来 至于我的方法,我不需要知道文件变化,我的实现是在源不断写入的时候,不断去读增量的写入,读不到表示还没有写入,忽略即可,一直读到源完成,所以我的处理里面,对源定入的文件是一直保持打开的,难道我要读一次,把位置记录下来,然后关闭了重新打开才能读增量? (源的开始和结束我是知道的,请看我最开始的需求,我的目标是对工具进行封装,把工具的文件写入截取到我自己要做的实现里面)
  • 打赏
  • 举报
回复
引用 18 楼 zjcxc 的回复:
重定向目录没用啊,它又不能重定向到我的程序或者标准输出
如果你都不需要重定向文件输出目录只是文件名的话,你直接用filesystemwatcher监控文件是否写入完成(似乎也没有接口,只能监控文件大小变化是否停止),发现写入完成后直接重命名文件或打开文件即可。 你现在能简单整理一下你的需求吗?我感觉你表达的需求我理解的不够准确。
zjcxc 2018-02-01
  • 打赏
  • 举报
回复
重定向目录没用啊,它又不能重定向到我的程序或者标准输出
  • 打赏
  • 举报
回复
引用 16 楼 zjcxc 的回复:
.net 实现的基本没找到,c/C++ 的多,只是俺也看不懂,所以来求助
  ntfs下用 mklink 可以直接重定向目录…………这个是系统级实现完成的,所以如果没有特别需求,直接这样做即可。 这个你试过吗?就一句cmd命令就行。
zjcxc 2018-02-01
  • 打赏
  • 举报
回复
.net 实现的基本没找到,c/C++ 的多,只是俺也看不懂,所以来求助
  • 打赏
  • 举报
回复
引用 5 楼 zjcxc 的回复:
举个实际的例子: 比如 sql server 的 BCP 工具,它只能 BCP OUT 到文件,再从文件 BCP IN 如果我不想通过文件缓存,我想数据直接到目标服务器,如果它支持管道(或者是我能包装成支持管道),一条命令就行: bcp out | bcp in 这不省事很多吗?(当然,这个需求是可以用其他不缓存文件的文件来袜,我只是举例说明我的需求而已) .... 最近 Linux 的管道用多了,回头看 Windows 的操作,很少支持管道的,所以想着是否可以对某些工具封装封装
windows继承了dos下的很多管道,但是有权限操作的管道不多。 不过 dir >filelist.log 还是很好用的,我常用这个生成文件夹说明文档。
  • 打赏
  • 举报
回复
引用 13 楼 From_TaiWan 的回复:
没研究过,但我知道,需要调用底层win32 API解决,先收藏,有空研究 一旦实现,是有些价值的
ntfs下用 mklink 可以直接重定向目录…………这个是系统级实现完成的,所以如果没有特别需求,直接这样做即可。
秋的红果实 2018-02-01
  • 打赏
  • 举报
回复
没研究过,但我知道,需要调用底层win32 API解决,先收藏,有空研究 一旦实现,是有些价值的
  • 打赏
  • 举报
回复
windows系统是有映射目录的命令的,可以直接将一个目录映射为另一个目录,这个功能我觉得完全可以实现你的需求。
加载更多回复(17)

110,476

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧