Файловый вывод

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Kazanove
Сообщения: 41
Зарегистрирован: 24 фев 2016, 14:55

Да было именно дело в переменной i. заработало

переделал под считывание целой строки, а потом разбираю на столбцы

Код: Выделить всё

while ((fgets(arr, 100, pFile) != NULL)){
		istr = strtok(arr, "|");
		j = 0;
		while (istr != NULL){
			switch (j){
			case 0:
				strcpy(book[i].UDK, istr);
				break;
			case 1:
				strcpy(book[i].FullName, istr);
				break;
			case 2:
				strcpy(book[i].BookName, istr);
				break;
			case 3:
				book[i].cost = atof(istr);
				break;
			case 4:
				book[i].quantity = atoi(istr);
				break;
			default:
				break;
			}
			istr = strtok(NULL, "|");
			j++;
		}
		i++;
	}
да так немного проще
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

В памяти структура заполнена правильно. А вот ту первую строку, которая тебя смущает, формирует вот этот код:

Код: Выделить всё

case 0:
   printf("%s", istr); // ВОТ ЭТОТ!
   strcpy(book[i].UDK, istr);
   break;
Если бы ты в дебагере во время пошагового выполнения программы переключился бы в консоль и посмотрел, что и в какой момент туда выводится, то ты бы это и сам понял :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Kazanove
Сообщения: 41
Зарегистрирован: 24 фев 2016, 14:55

а можно прочитать определенную строку из файла (к примеру 2-ю строку) не читая весь файл?
или нужно все ровно загружать построчно (через цикл) и когда дойду до той строки которая мне нужно,просто выйти из цикла?
и можно ли прочитать файл с конца в начало?
или же опять прочитать файл в массив, а массив перевернуть?
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Прочитать вторую строку с начала файла довольно просто. Достаточно всего два раза вызвать функцию fgets() и дальше можно не читать. Читать файл с конца в начало в принципе тоже можно, но только если заранее знаешь, сколько байт тебе нужно отступать от конца файла. Иначе овчинка выделки не стоит, только усложнишь себе задачу.
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Надеюсь, ты понимаешь, что понятие "строка" существует только в текстовом редакторе (который открывает и вычитывает весь файл в момент запуска, так что может посчитать переводы кареток во всём тексте).

По факту же, все функции, которые читают данные из файла, не могут сразу переходить на строку с определённым номером, так как пока байты из файла не извлечены, определить где заканчивается одна строка и начинается следующая невозможно.

Если же ты знаешь линейную позицию символа в файле (то есть номер байта от начала файла, к которому нужно перейти), то тогда ты действительно можешь пропустить все предыдущие байты, вызвав fseek.

Из этого, кстати, сам собой напрашивается вывод. Если ты будешь дополнять все строки в своём файле пробелами так, чтобы они все были гарантированной длины, то ты без проблем сможешь вычислять необходимые смещения от конца файла и как бы "бегать" по строкам с помощью fseek.

Код: Выделить всё

1234   |safdasdf      |sadfsda                |333,00    |2    |
1234   |asdff         |sadfasdf               |3334,00   |12   |
1233   |qweerr        |sadfsgad sadgsdfg      |233,00    |3244 |
12344  |wqerasdfasdf  |sadfasd asdf asdf adsf |123456,00 |123  |

Код: Выделить всё

// Opening of the file.
FILE* fl = fopen(...);

// Line number that must be read (0-based).
int line_number = 3;

// 64 symbols in one line, plus 2 system sybmols for line returning (0xD, 0xA - carriage return and line feed).
// And all this stuff is to be multiplied by the number of lines.
int offset = (64 + 2) * line_number; 

// Move file pointer to the calculated position.
fseek(fl, offset, SEEK_SET);

// Read 3-th line.
fgets(..., fl);
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Есть другой способ: если сам программно пишешь строки в текстовый файл, то можно параллельно записывать смещения и длины строк в отдельный индексный файл. Т.е. это бинарный файл, в котором будут последовательно записаны структуры типа

Код: Выделить всё

typedef struct STRING_INDEX_STRUCT
{
    long offset;  // смещение внутри файла
    long length;  // длина строки
} STRING_INDEX;
В этом случае у тебя будет полная информация о расположении текстовых строк внутри файла, соответственно появится возможность читать строки из файла в произвольном порядке.
Если же у тебя нет такого индексного файла, то его можно будет создать с помощью несложной утилитки, которая будет предварительно читать "сырой" текстовый файл построчно и записывать в индексный файл информацию о расположении строк.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Ну, наверное, это не самый удачный приём, хотя он и имеет право на жизнь. Дело в том, что он представляет собой нечто среднее между двумя крайностями - чисто текстовым подходом (медленное позиционирование, но возможность править файл руками) и чисто бинарным подходом (быстрое позиционирование, но отсутствие возможности править руками). Включал бы предложенный метод плюсы от двух крайностей - цены бы ему не было. Но он включает только минусы, так как файл руками не поправишь, но при этом позиционирование не такое быстрое, как у чисто бинарного подхода, и, ко всеми прочему, ещё и нужен какой-то дополнительный файл, постоянно нуждающийся в обновлении.

Для того, чтобы решить, каким подходом лучше всего пользоваться, предлагаю в первую очередь определить нужна ли тебе возможность править файл базы данных руками. Если нужна - то используй чисто текстовый подход. Если не нужна - чисто бинарный. Промежуточные подходы, как показывает практика - от лукавого :)

P.S. Если что, под чисто бинарным подходом я подразумеваю оперирование данными с помощью fread/fwrite.

P.P.S. И если уж совсем о правильных вещах говорить, то для работы с базами данных наиболее правильным выходом будет использование готовых решений, коих в интернете масса (например SQLite). Но это уже потом, когда накопишь опыт. На данный момент реализуемая задача более, чем соответствует своим целям - натренировать начинающего программиста.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Предложенный мной вариант взят из реальной жизни. К примеру база данных формата dBase (расширение .DBF) В нём каждая таблица по сути является текстовым файлом, у которого все записи являются строками фиксированной длины. Там лишь заголовок бинарный. Но к нему так же прилагается индексный файл для поиска записей через отсортированный массив ключевых значений. Ещё прилагаются файлы с массивами данных типа BLOB и МЕМО. Понятно, что руками эти файлы не редактируют (хотя лет 25-30 назад наверно и такой способ тоже имел место), и появилась эта система очень давно, однако ведь она до сих пор существует.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Это уже описан классический индекс-файл. Он используется для ускорения поиска. В файле хранятся не просто смещения строк. Хранимые значения ещё и пересортированы в таком порядке, чтобы соответствующие им строки из исходного файла шли по алфавиту. В таком случае смысл в индексном файле конечно же есть. Более того, собственно, это то, для чего индексные файлы и используются в базах данных.

А вот использовать индексный файл просто для того, чтобы хранить смещения строк в том порядке, в котором они идут в исходном файле - смысла не много.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

В общем вывод можно сделать такой: использовать текстовый файл для хранения структурированных данных конечно можно, но как промежуточный формат для экспорта-импорта данных из разных приложений.
Например: если в качестве разделителя столбцов использовать символ ; (точка с запятой), а расширение файла поменять с TXT на CSV, то этот файл можно открыть как таблицу при помощи Microsoft Excel или Libre Office Calc.
Числовые данные в текстовом файле так же представлены в виде текста. Это удобно для их отображения в разных таблицах и отчётах, но для математической обработки данных их необходимо преобразовывать в числа.
Если представлять все записи в виде строк фиксированной длины, то почти половина файла будет заполнена пробелами, что не оптимально с точки зрения размеров файла и выделения памяти.
Что же касается идеи, которую предложил WinMain, то она требует доработки.
Прочитать исходный текстовый файл и сформировать из него массив индексных структур - это правильно, только записывать его нужно не в отдельный файл, а вместе с исходным текстом сохранить в единый файл, где будут представлены и текстовые строки и бинарные индексы.
Ещё в начало этого файла необходимо будет записать специальную заголовочную структуру, содержащую всю техническую информацию для правильного чтения последующих данных.
Поумнеть несложно, куда труднее от дури избавиться.
Ответить