none
FileStream寫出的檔案尾部加上了非預期的資訊 RRS feed

  • 一般討論

  • 各位先進好, 這個問題困擾了我半天...

    因為不好下key word,所以也在網路上搜不到答案或有用的解法,只好硬著頭皮問了...

    我有一支程式做以下工作(我先用虛擬碼介紹):

    準備:一個string[],一個文字檔A.txt,一個文字檔C.txt。

    流程:

    1. 用FileStream開啟目的檔result.txt
    2. 讀取A.txt並呼叫FileStream的write寫到result.txt
    3. 逐一取出string[]中的string(在此稱它為B),寫到result.txt (string[]的長度只有1,是一個約250kb長的字串)
    4. 讀取C.txt,寫到result.txt
    5. 呼叫FileStream的flush
    6. 呼叫FileStream的close

    result.txt的結果預期是:A+B+C

    但執行結果卻是:A+B+C+部份的B(長度大概10KB)

    我看過程式碼,查過buffer相關的文章,但仍找不出具體的原因。這問題在我的開發環境中是不會發現的,反而在客戶的server上發生。他們的環境是Win2k8 SR,framework應該是3.0以上版本。

    程式的部份是:

                        FileStream fs = null;
                        try
                        {
                            string pathAndFName = saveTo;
                            fs = new FileStream(pathAndFName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
    
                            byte[] tmp = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportHeader.txt");
                            fs.Write(tmp, 0, tmp.Length);// write header
    
                            // write sheet
                            for (int i = 0; i < reports.Length; i++)
                            {
                                tmp = Encoding.Default.GetBytes(reports[i]);
                                fs.Write(tmp, 0, tmp.Length);// write 
                            }
    
                            tmp = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportTailer.txt");
                            fs.Write(tmp, 0, tmp.Length);// write tailer
    
                            fs.Flush();
                        }
                        finally
                        {
                            if (fs != null) fs.Close();
                        }

    使用到的function ReadFile是:

            public static byte[] ReadFile(string pathAndFName)
            {
                FileStream myFile = null;
                byte[] data = null;
                try
                {
                    myFile = File.Open(pathAndFName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    BinaryReader myReader = new BinaryReader(myFile);
                    int dl = System.Convert.ToInt32(myFile.Length);
                    data = myReader.ReadBytes(dl);
                }
                finally
                {
                    if (myFile != null) myFile.Close();
                }
                return data;
            }

    麻煩大家給點意見...感謝...


    • 已編輯 jackmis 2012年2月7日 上午 09:12 同上...
    • 已變更類型 Bill ChungMVP, Moderator 2012年2月9日 上午 07:26 發問者自行找到原因, 非程式問題.
    2012年2月7日 上午 09:04

所有回覆

  • 試看看在每次的.Write後,馬上呼叫.Flush

    FileStream fs = null;
                       
    try
                       
    {
                           
    string pathAndFName = saveTo;
                            fs
    = new FileStream(pathAndFName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);

                           
    byte[] tmp = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportHeader.txt");
                            fs
    .Write(tmp, 0, tmp.Length);// write header
                            fs.Flush();


                           
    // write sheet
                           
    for (int i = 0; i < reports.Length; i++)
                           
    {
                                tmp
    = Encoding.Default.GetBytes(reports[i]);
                                fs
    .Write(tmp, 0, tmp.Length);// write
                                fs.Flush();


                           
    }

                            tmp
    = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportTailer.txt");
                            fs
    .Write(tmp, 0, tmp.Length);// write tailer

                            fs
    .Flush();
                       
    }
                       
    finally
                       
    {
                           
    if (fs != null) fs.Close();
                       
    }


    2012年2月7日 上午 09:22
  • 試試看改成用三個byte array去接

                byte[] header = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportHeader.txt");
                fs.Write(header, 0, header.Length);// write header

                // write sheet
                for (int i = 0; i < reports.Length; i++)
                {
                    byte[] content = Encoding.Default.GetBytes(reports[i]);
                    fs.Write(content, 0, content.Length);// write 
                }


                byte[] tailer = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportTailer.txt");
                fs.Write(tailer, 0, tailer.Length);// write tailer

                


    以下為簽名檔,如果你愛拉椅子坐那就是你的問題。
    先查MSDN文件庫
    再用GOOGLE搜尋
    才到論壇來發問

    這是論壇不是技術支援中心
    沒有人得無償解答你的問題

    在標題或文章註明很急
    不會增加網友回覆速度

    2012年2月7日 上午 09:55
  • 不成功...orz

    執行結果一樣。我發現一件事,就是執行結果會一樣。

    我是說,發生此狀況並非隨機的結果,buffer中被寫出的資訊位置不會動,而產出同樣的結果。

    我幾乎可以肯定是buffer裡的東西被寫出來了,因為我把A+B寫成另一個檔,發現結果竟是A+B+部份的B;且大小等於先前產出的A+B+C+部份的B,其中部份的B,頭部的部份被C取代掉。

    可怕的是....只有客戶的電腦才會這樣....orz

    客戶產出的檔案大小約230k

    我自己試過10多k的、7MB的,都不會有此結果...


    我有找到一篇文章「可能」和此問題有關(下面的url),但是不敢肯定,尤其它可能是for WinCE的,所以也還在研究要怎麼解決...

    http://www.pcreview.co.uk/forums/filestream-flush-not-flushing-t1311644.html


    • 已編輯 jackmis 2012年2月8日 上午 06:53
    2012年2月8日 上午 06:23
  • 這太詭異了

    可以方享一下  輸出檔案 完整的cs檔 + reports的完整內容嗎?


    以下為簽名檔,如果你愛拉椅子坐那就是你的問題。
    先查MSDN文件庫
    再用GOOGLE搜尋
    才到論壇來發問

    這是論壇不是技術支援中心
    沒有人得無償解答你的問題

    在標題或文章註明很急
    不會增加網友回覆速度

    2012年2月8日 上午 07:07
  • 恐怕不好把完整的文件秀出來...

    我在程式碼中把每個write後面把每個tmp都寫到另一份檔案,發現只有A、C是正常的,單寫B的時後,結果也變成B+部份的B (部份的B,大約是B的中間某段)

    我懷望疑可能B本身就是錯的,於是我把它寫到log裡(log4net),結果更可怕...

    2012-02-08 15:29:20,954 INFO  Com.ExportReportFrame - 把內容寫到log:
    2012-02-08 15:29:20,960 INFO  Com.ExportReportFrame - <Worksheet ss:Name="comm(T)"><ss:Table ss:DefaultColumnWidth="83"><ss:Row><ss:Cell><ss:Data ss:Type="String">報表名稱:每日回應時間統計報表</ss:Data></ss:Cell></ss:Row>
    <ss:Row><ss:Cell><ss:Data ss:Type="String">報表時間:2012/02/06</ss:Data></ss:Cell></ss:Row>
    
    ..(要寫出的部份...中略)
    
    <ss:Cell ss:StyleID="data1"><ss:Data ss:Type="String">200</ss:Data></ss:Cell>
    </ss:Row>
        </ss:Table>
      </Worksheet>
    2012-02-08 15:29:20,972 INFO  Com.ExportReportFrame - ===============
    2012-02-08 15:29:23,012 INFO  Com.ExportReportFrame - 下載了日報表(2012/02/06)
    :Data ss:Type="String">6</ss:Data></ss:Cell>
    <ss:Cell ss:StyleID="data1"><ss:Data ss:Type="String">6</ss:Data></ss:Cell>
    <ss:Cell ss:StyleID="data1"><ss:Data ss:Type="String">200</ss:Data></ss:Cell>
    ..(多出來的部份...略)

    我寫log的程式是:

                                log.Info("把內容寫到log:");
                                log.Info(reports[i]);
                                log.Info("===============");

    結果竟然在『====...』後面多了一段@@,『下載了日報表(2012/02/06)』之後的那些是多出來的。沒想到連log4net都受到干擾了...現在我懷疑reports[i]這個string裡可能有些字元和.Net的outstream的控制字元有衝突...否則怎麼可能會這樣...

    ,但裡面只有用「\r\n」,這可能出事嗎...唉

    2012年2月8日 上午 08:52
  • 看不出來有什麼問題

    你的程式是跑多執行緒嗎?

    另外, 可以試試看改成用 StreamWriter類別做輸出

    參考MSDN 範例


    以下為簽名檔,如果你愛拉椅子坐那就是你的問題。
    先查MSDN文件庫
    再用GOOGLE搜尋
    才到論壇來發問

    這是論壇不是技術支援中心
    沒有人得無償解答你的問題

    在標題或文章註明很急
    不會增加網友回覆速度

    2012年2月8日 下午 12:36
  • 各位先進好, 這個問題困擾了我半天...

    因為不好下key word,所以也在網路上搜不到答案或有用的解法,只好硬著頭皮問了...

    我有一支程式做以下工作(我先用虛擬碼介紹):

    準備:一個string[],一個文字檔A.txt,一個文字檔C.txt。

    流程:

    1. 用FileStream開啟目的檔result.txt
    2. 讀取A.txt並呼叫FileStream的write寫到result.txt
    3. 逐一取出string[]中的string(在此稱它為B),寫到result.txt (string[]的長度只有1,是一個約250kb長的字串)
    4. 讀取C.txt,寫到result.txt
    5. 呼叫FileStream的flush
    6. 呼叫FileStream的close

    result.txt的結果預期是:A+B+C

    但執行結果卻是:A+B+C+部份的B(長度大概10KB)

    我看過程式碼,查過buffer相關的文章,但仍找不出具體的原因。這問題在我的開發環境中是不會發現的,反而在客戶的server上發生。他們的環境是Win2k8 SR,framework應該是3.0以上版本。

    程式的部份是:

                        FileStream fs = null;
                        try
                        {
                            string pathAndFName = saveTo;
                            fs = new FileStream(pathAndFName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
    
                            byte[] tmp = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportHeader.txt");
                            fs.Write(tmp, 0, tmp.Length);// write header
    
                            // write sheet
                            for (int i = 0; i < reports.Length; i++)
                            {
                                tmp = Encoding.Default.GetBytes(reports[i]);
                                fs.Write(tmp, 0, tmp.Length);// write 
                            }
    
                            tmp = Util.Utility.ReadFile(MyEnv.sysCfgPath + "ReportTailer.txt");
                            fs.Write(tmp, 0, tmp.Length);// write tailer
    
                            fs.Flush();
                        }
                        finally
                        {
                            if (fs != null) fs.Close();
                        }

    使用到的function ReadFile是:

            public static byte[] ReadFile(string pathAndFName)
            {
                FileStream myFile = null;
                byte[] data = null;
                try
                {
                    myFile = File.Open(pathAndFName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    BinaryReader myReader = new BinaryReader(myFile);
                    int dl = System.Convert.ToInt32(myFile.Length);
                    data = myReader.ReadBytes(dl);
                }
                finally
                {
                    if (myFile != null) myFile.Close();
                }
                return data;
            }

    麻煩大家給點意見...感謝...


    Hi~ 針對你的問題,及眾人先前的討論,再加上我剛去找資料,推測如下的結果,敬酌參:

    Ref: [C#]關於FileStream的一些使用與操作 (http://www.dotblogs.com.tw/shinyo.her/archive/2010/10/05/18107.aspx)

    在上文中有提到很關鍵的一句話(算是經驗吧!),如后: (我標粗體是我覺得問題所在!)

    -----------------------------------------------

    開啟資料

    這是使用FILESTREAM開啟文件夾的典型範例 ,重要的是要始終關閉stream。如果你不關閉它可能會需要一分鐘之後才能再次開啟文件(它將等待garbage collector釋放FileStream,並關閉該文件)。

    -----------------------------------------------


    提出值得你思考的問題點如下:

    1. 你是否重覆操作同一檔案文件?同時,間隔沒有一分鐘? (依上述引用的論點推定)  >> 一下 Read  馬上就 Write ...
        建議可以分別+綜合試試:
        一、 建立兩個 FileStream ,分別處理 Write 及 Read,如 fs1.Write();   ///  fw2.Read();
        二、 是否在處理下一檔案前, sleep 一下 (雖然這很不正確,但為了找出問題點.....)

    2. 客戶端的環境與你的電腦環境是否一樣? 硬體等級差異? ( CPU 速度、 RAM大小 、在執行你的程式時是否有執行其他吃資源的程式?)

    3. 在你的 Code 中除了看到你有 fs.Close(); 外,是否建議再加上 fs.Dispose();  [Ref: http://msdn.microsoft.com/en-us/library/system.io.filestream.dispose.aspx ]

    4. 你的檔案路徑的變數 (Ex:pathAndFName) 在設定時是有用到 @ 嗎?  還是用 \\ 來表示?  [Ref: http://paladinprogram.blogspot.com/2011/11/filestream.html ]

    5. 試試 FileStream.Lock() 及 FileStream.Unlock() 方法的搭配應用,來防止不必要的寫入/讀出作動。  [ Ref:  http://msdn.microsoft.com/zh-tw/library/system.io.filestream.lock%28v=vs.80%29.aspx ]

    6. 可參考 FileStream.Finalize 方法,來確認釋出資源   [Ref: http://msdn.microsoft.com/zh-tw/library/system.io.filestream.finalize%28v=vs.80%29.aspx ]

    上述 6 點請  分別 / 綜合 試試,並排除看看!



    逐步學習,逐夢踏實;腳步要踩穩,這樣下一步才不會跌倒。 http://www.dotblogs.com.tw/nobel12


    2012年2月9日 上午 01:16
  • 問題已經解開了,不好意思,在此向大家道歉,原因和我的程式無關。

    我寫出的檔案,客戶會透過windows內建的遠端桌面去取回來。這些多出來的資料,就是那時才加上去的。因此,該檔案在遠端機器上時是正確無誤的。

    還好想起以前在其他客戶那發生過程式透過遠端桌面copy就無法執行的問題,因為檔案大小不一致。

    抱歉,打擾大家了。不過,遠端桌面也是微軟提供的,所以搔擾到自家論壇也ok吧XD

    2012年2月9日 上午 07:18