Программа должна считывать из текстового файла (.txt) весь текст и записывать его в массив строк по 100 символов. Файлы большого объема (от 10 Мбайт). Использую File.ReadAllText для загона всего текста в одну строку, а потом ее бью на части и загоняю в массив строк. Интерфейс программы сразу же "не отвечает". Можно это сделать как-то быстрее и проще? Или тогда лучше использовать async/await?
Вот, отличное решение, через метод-расширение:
public static class StringExtensions
{
public static IEnumerable<string> SplitChunk(this string s, int chunkSize)
{
int chunkCount = s.Length / chunkSize;
for (int i = 0; i < chunkCount; i++)
yield return s.Substring(i * chunkSize, chunkSize);
if (chunkSize * chunkCount < s.Length)
yield return s.Substring(chunkSize * chunkCount);
}
}
private async Task<IEnumerable<string>> GetAllStrings(int chunkSize, string filePath)
{
using (var sr = File.OpenText(filePath))
{
var rawText = await sr.ReadToEndAsync();
var text = rawText.Replace(Environment.NewLine, "");
return text.SplitChunk(chunkSize).ToList();
}
}
Использование:
var listChunk = await GetAllStrings(100,"c:\\temp\\2.txt");
Ещё одно улучшение вдвое по скорости, за счёт увеличения буфера до 4К:
List<string> SplitByChars(int chunkSize, string path)
{
List<string> result = new List<string>();
using (var f = File.OpenText(path))
{
var buffer = new char[4096];
StringBuilder currentLine = new StringBuilder(chunkSize);
int readCount;
do
{
readCount = f.ReadBlock(buffer, 0, buffer.Length);
for (int i = 0; i < readCount; i++)
{
char c = buffer[i];
if (c == '\r' || c == '\n')
continue;
currentLine.Append(c);
if (currentLine.Length == chunkSize)
{
result.Add(currentLine.ToString());
currentLine.Clear();
}
}
} while (readCount > 0);
if (currentLine.Length > 0)
result.Add(currentLine.ToString());
}
return result;
}
Старый вариант:
IEnumerable<string> SplitByChars(int chunkSize, string path)
{
List<string> result = new List<string>();
using (var f = File.OpenText(path))
{
var buffer = new char[chunkSize];
StringBuilder currentLine = new StringBuilder(chunkSize);
int readCount;
do
{
var oldLength = currentLine.Length;
var rest = chunkSize - currentLine.Length;
readCount = f.ReadBlock(buffer, 0, rest);
currentLine.Append(buffer, 0, rest);
currentLine.Replace("\r", "", oldLength, rest);
currentLine.Replace("\n", "", oldLength, currentLine.Length - oldLength);
if ((readCount == 0 && currentLine.Length > 0) ||
currentLine.Length == chunkSize)
{
result.Add(currentLine.ToString());
currentLine.Clear();
}
} while (readCount > 0);
}
return result;
}
Я старался не грузить память чтением длинных строк, максимальное потребление памяти — один буфер размером в chunkSize
и один StringBuilder
с capacity в chunkSize
.
Пользоваться так:
var result = await Task.Run(() => SplitByChars(100, path));
Предыдущий вариант с ReadBlockAsync
был примерно втрое медленнее.
Здесь слишком много работы «вручную», возможно, есть более изящное решение.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Как сформировать цифровую подпись интеркассы в aspnet mvc
Не могу найти никакой документации по вопросу, о том, что означают различные значки и пиктограммы в VS2015Пользуясь отладчиком столкнулся с непонятными...