一、C#數據類型 值類型:直接訪問數據的值。有基本數據類型(byte / short / int / long / float / double / char / bool)、struct、enum; 引用類型:訪問數據的存儲地址。有class、interface、數組、委托、stting; 值類型 ...
一、前言
業務需要讀取txt的內容,導入到資料庫當中,博主百度了各種方法,大部分都會導致記憶體溢出異常,由此結合網上的各種方法,解決了該異常。
二、程式框架
.NET 4.5
WinForm
三、具體實現
1.1 TXT結構
可以看到該文件大小300多兆,裡面的條數差不多60w左右,每行當中的數據使用Tab分割
1.2 代碼
private void NewInsert1306(string fileDir) { FileStream fs = new FileStream(fileDir, FileMode.Open, FileAccess.Read);//創建一個文件流 參數(文件位置,打開此文件(如果沒有會拋異常),文件訪問許可權(只讀)) StreamReader sr = new StreamReader(fs);//創建一個txt讀取流,從位元組流中讀取字元 參數(流) using (var db = new CFTech.His.Models.DbContext()) { try { Stopwatch sw = new Stopwatch();//計時器 sw.Start();//開始計時 int num = 0;//計算總條數 db.BeginTransaction();
//死迴圈,由於不知道到底有幾行,跳出時機在迴圈體內部判斷 while (true) { var arrList = new List<string>();//存放讀取的數據 while (true) { var str = sr.ReadLine();//讀取一行內容返回改行的字元串(一個換行符一行),fs有一個fs.position屬性(流的位置),該屬性在進行任何讀取操作時會根據讀取的實際情況進行移動,當該位置到達流的末尾時,此方法返回null,該位置也可手動設置fs.position=xxx(long類型) if (str == null) break;//跳出時機就是讀完的時候 arrList.Add(str); if (arrList.Count > 10000) break;//該跳出用於入庫,博主這裡10000條入一次庫 } if (arrList.Count == 0) break;//當存放數據的list條數為0時,迴圈就可以結束了 num += arrList.Count(); ResBase res = Insert1306(arrList);//該方法就是具體的入庫操作了,可根據自己的實際情況去寫 if (res.ErrCode == -1) { MessageBox.Show(res.ErrMsg); return; } } db.CommitTransaction(); fs.Close();//釋放文件流 sw.Stop();//停止計時 MessageBox.Show("入庫條數:" + num.ToString()+"------" + "耗時:" + sw.Elapsed); return; } catch (Exception e) { MessageBox.Show(e.Message); db.RollbackTransaction(); } } }
1.3效率(資料庫:Oracle,orm框架:fireasy)
該方法為同步方法,全在主線程上操作,效率肯定沒有非同步快,UI會出現阻塞假死情況,以後在研究吧,差不多1分鐘入庫6w多,由於行業性質,勉強能接受吧
1.4遇到的坑
這是同事之前用的方法,他也沒想到會遇到這麼大的txt,該方法讀取文件中的所有行,並且將每行數據轉換為數組,對於小文件很方便,但是當文件大於一定程度時,必定會拋記憶體溢出異常,至於到底支持多大的文件,就沒有具體測試了(個人認為和記憶體無關,電腦為16G記憶體,運行此方法時還沒開始跑記憶體就直接拋了異常,可能是框架原因,親測在core裡面,使用相同方法,讀取同一個20w行的文本,framework直接拋異常,core成功運行)
END-----------------歡迎大家留言討論