Здравствуйте!
Я не являюсь программистом C++.
Задача в следующем.
Есть файл, который открывается как бинарный. Проблема в скорости обработки.
Нужны биты в едином массиве для обработки, например, алгоритмом Хаффмана.
Проблема скорости возникла уже на на файле размером 7Мб.
Если есть люди, которые хорошо разбираются в С++, подскажите пожалуйста, как максимально быстро читать на лету, либо загрузить в массив файл в двоичного представлении, для обработки обычными конструкциями "if..else"? Файлы размером до 10Гб.
Пример:
файл "1.txt"
открываем, читаем и получаем биты 0110111011.....01110 для обработки алгоритмом.
(Ранее задавал вопрос здесь же. К сожалению, предложения "профессионалов" оказались в разы, если не в 10 раз, хуже того, что я сам придумал и реализовал на малознакомом языке программирования.)
Спасибо.
C/C++
Бинарные данные C++. Как быстрее?
В чём конкретно проблема с производительностью? Проблему надо сначала определить, а потом уже решать. Иначе это не решение, а угадайка, вроде той, которой занимаются ИИ и два безмозглых бота, скопировавшие тексты от чатгпт.
Надеюсь, ты понимаешь, что для загрузки в память 10 Гб тебе потребуется более 10 Гб на сам файл, и ещё столько же на кодирование Хаффманом? На твоём железе столько памяти вообще есть? Если данные уходят в своп, о производительности можешь забыть. Это не школьная информатика, где можно оперировать абстракциями и не думать о размере данных.
Однопроходным алгоритмом реализовать не получится, т.к. нужно вначале собрать частоты. Если символы имеют одинаковое распределение по всему файлу, то можно собирать частоты по части данных, например, по первым 10 Мб. Но здесь появляется риск, что алгоритм станет неоптимальным. Кстати, посмотри вообще асимптотику своего алгоритма, она должна быть не более, чем линейной от объёма данных и линейно-логарифмической от размера алфавита. Если больше - меняй алгоритм.
Сам ввод-вывод насколько эффективно делается? Нужно читать и писать бинарные данные, без всяких надстроек вроде поиска конца строки, и ввод-вывод должен быть буферизованным. Обрабатывать надо не всё сразу, а кусками, помещающимися в оперативку (учитывая, что там ещё файловый кэш, система и другие процессы). Прочитал блок - обработал - выкинул исходные данные - прочитал следующий блок. Так делаем и для сбора статистики, и для самого кодирования.
Если и это не помогает, ставь более быстрый носитель и/или больше оперативки. Когда речь о файлах в десятки гигабайт, нужен SSD, обеспечивающий хорошую скорость по всему объёму, а не цыганское творение маркетологов, которых в рознице 99%.
Надеюсь, ты понимаешь, что для загрузки в память 10 Гб тебе потребуется более 10 Гб на сам файл, и ещё столько же на кодирование Хаффманом? На твоём железе столько памяти вообще есть? Если данные уходят в своп, о производительности можешь забыть. Это не школьная информатика, где можно оперировать абстракциями и не думать о размере данных.
Однопроходным алгоритмом реализовать не получится, т.к. нужно вначале собрать частоты. Если символы имеют одинаковое распределение по всему файлу, то можно собирать частоты по части данных, например, по первым 10 Мб. Но здесь появляется риск, что алгоритм станет неоптимальным. Кстати, посмотри вообще асимптотику своего алгоритма, она должна быть не более, чем линейной от объёма данных и линейно-логарифмической от размера алфавита. Если больше - меняй алгоритм.
Сам ввод-вывод насколько эффективно делается? Нужно читать и писать бинарные данные, без всяких надстроек вроде поиска конца строки, и ввод-вывод должен быть буферизованным. Обрабатывать надо не всё сразу, а кусками, помещающимися в оперативку (учитывая, что там ещё файловый кэш, система и другие процессы). Прочитал блок - обработал - выкинул исходные данные - прочитал следующий блок. Так делаем и для сбора статистики, и для самого кодирования.
Если и это не помогает, ставь более быстрый носитель и/или больше оперативки. Когда речь о файлах в десятки гигабайт, нужен SSD, обеспечивающий хорошую скорость по всему объёму, а не цыганское творение маркетологов, которых в рознице 99%.
Аркадий М
Спасибо за ответ от человека ;-). Памяти 16Гб, ССД Самс860. 10Гб максимум - это вторая задача, на первом этапе файл размером 1Гб. Да, буду пробовать через буфер 1Мб. По Хаффману понимаю, что он не однопроходный ;-)
Аркадий М
Да, буду пробовать, есть комп с nvme еще и более быстрым процессором, но там памяти меньше. Спасибо еще раз, хороших выходных! )))
Работа с бинарными файлами в C++ может быть довольно быстрой, если использовать правильные методы чтения и записи. В C++ вы можете использовать класс `std::ifstream` с флагом `std::ios::binary` для чтения бинарного файла. Для считывания данных из файла в буфер (например, массив) вы можете использовать метод `read()`.
Важно отметить, что скорость чтения бинарных данных будет зависеть от нескольких факторов, включая размер буфера чтения и скорость доступа к диску. Следующий код показывает, как можно быстро прочитать бинарный файл в массив в C++:
В этом примере используется метод `std::ifstream::read`, который позволяет считывать данные непосредственно в память. Вектор `buffer` содержит все данные файла после выполнения этого кода.
Обратите внимание, что вы можете хранить бинарные данные как массив `char`, но работать с ними как с битами с использованием побитовых операторов.
Пожалуйста, учтите, что обработка больших файлов может потребовать большого количества памяти и CPU. Если ваш файл слишком большой для загрузки в память целиком, вам может потребоваться использовать более сложные методы обработки, такие как чтение и обработка файла по частям.
Кроме того, обратите внимание, что скорость чтения из файла также может зависеть от скорости вашего жесткого диска. Возможно, вы захотите проверить скорость чтения данных с диска, чтобы убедиться, что это не является узким местом в вашем приложении.
Важно отметить, что скорость чтения бинарных данных будет зависеть от нескольких факторов, включая размер буфера чтения и скорость доступа к диску. Следующий код показывает, как можно быстро прочитать бинарный файл в массив в C++:
#include
#include
int main() {
std::ifstream file("1.txt", std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector buffer(size);
if (file.read(buffer.data(), size))
{
/* теперь данные файла находятся в векторе buffer */
}
return 0;
}
В этом примере используется метод `std::ifstream::read`, который позволяет считывать данные непосредственно в память. Вектор `buffer` содержит все данные файла после выполнения этого кода.
Обратите внимание, что вы можете хранить бинарные данные как массив `char`, но работать с ними как с битами с использованием побитовых операторов.
Пожалуйста, учтите, что обработка больших файлов может потребовать большого количества памяти и CPU. Если ваш файл слишком большой для загрузки в память целиком, вам может потребоваться использовать более сложные методы обработки, такие как чтение и обработка файла по частям.
Кроме того, обратите внимание, что скорость чтения из файла также может зависеть от скорости вашего жесткого диска. Возможно, вы захотите проверить скорость чтения данных с диска, чтобы убедиться, что это не является узким местом в вашем приложении.
Аркадий М
Спасибо, попробую, но это напоминает то, что мне и до этого порекомендовали и оно было медленное... Ответы прямо как от ChatGPT ))))
Привет!
Если вам нужно чтение файла в бинарном режиме, один из наиболее эффективных и простых способов - это использовать функцию fread ().
Например, если вы хотите прочитать 1024 байта файла "test.bin" и поместить данные в массив данных типа unsigned char, можно использовать следующий код:
#include <cstdio>
int main()
{
FILE *fp = fopen("test.bin", "rb");
if(fp == nullptr) {
printf("Ошибка открытия файла");
return 1;
}
unsigned char data[1024];
fread(data, sizeof(unsigned char), 1024, fp);
fclose(fp);
return 0;
}
В этом примере fopen() открывает файл "test.bin" в бинарном режиме, определяющемся символом "b" в качестве второго аргумента. Это важно, потому что в бинарном режиме fread() не выполнит автоматическое преобразование символов перевода строки на Windows.
Функция fread() читает блок данных размером sizeof(unsigned char) в размере 1024 (третий аргумент) из файла в массив data.
Если вам нужно работать с битами, вы можете рассмотреть использование библиотеки BitMagic, которая предоставляет API для работы с битами. Библиотека поддерживает множество операций, таких как объединение, пересечение и дополнение наборов битов.
Еще одна возможность, которую можно рассмотреть, - это использование битовых масок для доступа к отдельным битам в байтах. Это может быть немного сложным, но может быть быстрее, чем использование библиотеки.
Например, если вы хотите получить седьмой бит из массива данных, вы можете использовать следующий код:
unsigned char data = /*некоторые данные*/;
unsigned char mask = 0x80;
bool seventhBit = (data & mask) != 0;
В этом примере создается маска, которая содержит единицу в седьмом бите и ноль в остальных битах. Затем происходит побитовое И маски с данными, чтобы получить значение седьмого бита.
Если вам нужно чтение файла в бинарном режиме, один из наиболее эффективных и простых способов - это использовать функцию fread ().
Например, если вы хотите прочитать 1024 байта файла "test.bin" и поместить данные в массив данных типа unsigned char, можно использовать следующий код:
#include <cstdio>
int main()
{
FILE *fp = fopen("test.bin", "rb");
if(fp == nullptr) {
printf("Ошибка открытия файла");
return 1;
}
unsigned char data[1024];
fread(data, sizeof(unsigned char), 1024, fp);
fclose(fp);
return 0;
}
В этом примере fopen() открывает файл "test.bin" в бинарном режиме, определяющемся символом "b" в качестве второго аргумента. Это важно, потому что в бинарном режиме fread() не выполнит автоматическое преобразование символов перевода строки на Windows.
Функция fread() читает блок данных размером sizeof(unsigned char) в размере 1024 (третий аргумент) из файла в массив data.
Если вам нужно работать с битами, вы можете рассмотреть использование библиотеки BitMagic, которая предоставляет API для работы с битами. Библиотека поддерживает множество операций, таких как объединение, пересечение и дополнение наборов битов.
Еще одна возможность, которую можно рассмотреть, - это использование битовых масок для доступа к отдельным битам в байтах. Это может быть немного сложным, но может быть быстрее, чем использование библиотеки.
Например, если вы хотите получить седьмой бит из массива данных, вы можете использовать следующий код:
unsigned char data = /*некоторые данные*/;
unsigned char mask = 0x80;
bool seventhBit = (data & mask) != 0;
В этом примере создается маска, которая содержит единицу в седьмом бите и ноль в остальных битах. Затем происходит побитовое И маски с данными, чтобы получить значение седьмого бита.
Похожие вопросы
- Как записать данные в бинарный файл C++
- Нужно найти в бинарном файле введенные пользователем данные.
- C++. Бинарный поиск. Объясните работу данной программы. Найдите такое число x, что , с точностью не менее 6 зн.С while
- Какой язык программирования работает быстрее и в каких случаях (Python и C++)?
- Задача по C++, анализ данных в двумерном массиве
- Необходимо вычислить аппроксимацию данных квадратичной функцией f(x)=at2+bt+c.Вычислить коэффициенты a,b и c
- Какие из этих книг вы посоветуете прочесть в первую очередь чтобы повысить свои знания в C/C++?
- Задача по C++
- День добрый \[-_-]/ вопрос по вузовскому программированию на си(C)
- Программирование C++ ПРОШУ ПОМОЧЬ!