ターゲットはディスクとRAMに制限されているため、リストを使用してファイルサイズを制限しています。これは私が今やっていることですが、より効率的な方法はありますか?
readonly List<string> LogList = new List<string>();
...
var logFile = File.ReadAllLines(LOG_PATH);
foreach (var s in logFile) LogList.Add(s);
var logFile = File.ReadAllLines(LOG_PATH);
var logList = new List<string>(logFile);
logFile
は配列であるため、List<T>
コンストラクターに渡すことができます。これにより、配列を繰り返し処理するとき、または他のIOクラスを使用するときの不要なオーバーヘッドがなくなります。
public List(IEnumerable<T> collection)
{
...
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
if (count == 0)
{
_items = _emptyArray;
}
else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
}
...
}
Evan Mulawskiの回答を少し更新して短くする
List<string> allLinesText = File.ReadAllLines(fileName).ToList()
代わりにジェネレータを使用しないのはなぜですか?
private IEnumerable<string> ReadLogLines(string logPath) {
using(StreamReader reader = File.OpenText(logPath)) {
string line = "";
while((line = reader.ReadLine()) != null) {
yield return line;
}
}
}
次に、リストを使用するように使用できます。
var logFile = ReadLogLines(LOG_PATH);
foreach(var s in logFile) {
// Do whatever you need
}
もちろん、List<string>
、その後、ファイルの内容全体をメモリに保持する必要があります。それを回避する方法は本当にありません。
[編集]
ログファイルの先頭をトリミングするためにこれを実行している場合、次のような操作を行うことでファイル全体の読み込みを回避できます。
// count the number of lines in the file
int count = 0;
using (var sr = new StreamReader("file.txt"))
{
while (sr.ReadLine() != null)
count++;
}
// skip first (LOG_MAX - count) lines
count = LOG_MAX - count;
using (var sr = new StreamReader("file.txt"))
using (var sw = new StreamWriter("output.txt"))
{
// skip several lines
while (count > 0 && sr.ReadLine() != null)
count--;
// continue copying
string line = "";
while (line = sr.ReadLine() != null)
sw.WriteLine(line);
}
まず、File.ReadAllLines
はファイル全体を文字列配列にロードします(string[]
)、リストへのコピーは冗長です。
次に、List
が内部の動的配列を使用して実装されることを理解する必要があります。これは、CLRがファイル全体を収容できるようになるまで、いくつかの配列を割り当ててコピーする必要があることを意味します。ファイルはすでにディスク上にあるので、メモリと速度を交換してディスクデータを直接処理するか、小さなチャンクで処理することを検討してください。
完全にメモリにロードする必要がある場合は、少なくとも配列に残してください:
string[] lines = File.ReadAllLines("file.txt");
本当にList
である必要がある場合は、1行ずつロードします。
List<string> lines = new List<string>();
using (var sr = new StreamReader("file.txt"))
{
while (sr.Peek() >= 0)
lines.Add(sr.ReadLine());
}
注:List<T>
には、容量パラメーターを受け入れるコンストラクターがあります。事前に行数がわかっている場合は、事前に配列を事前に割り当てることにより、複数の割り当てを防ぐことができます。
List<string> lines = new List<string>(NUMBER_OF_LINES);
さらに良いことに、ファイル全体をメモリに保存せずに、「オンザフライ」で処理します。
using (var sr = new StreamReader("file.txt"))
{
string line;
while (line = sr.ReadLine() != null)
{
// process the file line by line
}
}
可能であれば保管しないでください。メモリに制約がある場合は、それを読んでください。 StreamReaderを使用できます。
using (var reader = new StreamReader("file.txt"))
{
var line = reader.ReadLine();
// process line here
}
これは、LINQを使用する場合、1行ごとに文字列を読み取るメソッドにラップできます。
このように簡単に読むことができます。
List<string> lines = System.IO.File.ReadLines(completePath).ToList();
//this is only good in .NET 4
//read your file:
List<string> ReadFile = File.ReadAllLines(@"C:\TEMP\FILE.TXT").ToList();
//manipulate data here
foreach(string line in ReadFile)
{
//do something here
}
//write back to your file:
File.WriteAllLines(@"C:\TEMP\FILE2.TXT", ReadFile);
List<string> lines = new List<string>();
using (var sr = new StreamReader("file.txt"))
{
while (sr.Peek() >= 0)
lines.Add(sr.ReadLine());
}
私はこれを提案します... Grooの答え。
string inLine = reader.ReadToEnd(); myList = inLine.Split(new string [] {"\ r\n"}、StringSplitOptions.None).ToList();
この回答では、OutOfMemoryエラーが発生していたという元のポイントを見逃しています。上記のバージョンを続行する場合、システムにファイルをロードするための適切な連続RAMがない場合は必ずヒットしてください。
単にパーツに分割し、いずれかの方法でListまたはString []として保存する必要があります。
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
Environment.NewLine.toCharArrayも使用しますが、\ r\nで終わるいくつかのファイルでは動作しないことがわかりました。どちらかを試してみてください。うまくいくと思います。