LINUX.ORG.RU

считывние строк любой длины


0

0

Здравствуйте. Не подскажете как можно сие грамотно сделать? Надо 
организовать построчное чтенеи из файлов строк, длина которых 
непредсказуема. Я сдела так:

запоминаем тек. позицию
читаем число символов до перевода строки
выделяем необходимую память
передвигаемся к началу
читаем read() сколько надо


В принципе алгоритм работает, но неслабо грузит компьютер. А как можно еще ?
anonymous

а) Если весь файл представляется в виде последовательности строк:

1 считываешь файл в буфер fread/read -ом

2 в буфере делаешь замену всех '\n'-ов на '\0' и соотвествующим образом расставляешь указатели на строки.

б) Если необходимо считать только одну строку произвольной длины:

1 выделяешь буфер размером x байт

2 считываешь х байт из фала

3 Сканируешь считанные x байт

4 если в n-ом считанном байт был обнаружен '\n', то делаешь буферу realloc(n) иначе делаешь буферу realloc(2*х) и считываешь еще x байт, goto 3

Bob1
()
Ответ на: комментарий от Bob1

Угу, нужно последовательно считывать по одной строке из файлы. Весь файл в память не влезет. В вашем варианте б) возможно проблема - что если прочитается из файла больше, чем нужно? Пока думаю либо возвращать позицию в файле, либо использовать static буфер в функции

anonymous
()
Ответ на: комментарий от anonymous

Если из файла прочитается больше чем нужно ты урезаешь буфер до нужного размера (т.е до '\n'). Это делается realloc-ом. Заменяешь '\n' на '\0'. Откатываешь текущую позицию в файле на x-n символов назад.

Bob1
()
Ответ на: комментарий от anonymous

А зачем read()?
Читай себе обычным fgets() - больше одной строки он не прочитает.
А если прочитает меньше (строка слишком длинная) - выделяешь больший
буфер и дочитываешь тем же fgets().

Onanim
()
Ответ на: комментарий от anonymous

> Просто неохота делать fdopen(). Файл не тока для этого юзается :)

Ниасилил :-/
То есть возиться с изобретением велосипеда охота, а вызвать fdopen()
неохота? Ну тогда открывай файл с помощью fopen() :-)
Не, я понимаю, если у тебя был бы не файл, а сокет/пайп и тебе
надо было бы использовать это файл-дескриптор в select() - тогда stdio
может быть не самым лучшим вариантом. Но у тебя же простой файл (судя
по тому, что ты по нему seek'и делаешь)!

Onanim
()
Ответ на: комментарий от Onanim

А в чем велосипед ? Какое прям такое преимущество мне даст fgets() если строка прочитана не полностью ? Как я уже написал, в проге с файлом нужно работать в том числе и через read() для чтения больших кусков без разбора на строки. Тогда получается надо делать fdopen чтобы запахал fgets(). Ессно сделать это не сложно, но к чему? Не намного оно упростит дело. Имхо ессно ;)

anonymous
()
Ответ на: комментарий от anonymous

> Какое прям такое преимущество мне даст fgets() если строка прочитана
> не полностью ?

Производительность и краткость кода. Особенно в сравнении с
твоим алгоритмом, который ты привел в своем исходном постинге.

> Как я уже написал, в проге с файлом нужно работать в том числе и
> через read() для чтения больших кусков без разбора на строки.

Разве уже fread() отменили?

Ну если тебе так нужно - у Стивенса в UNPv1 есть пример.
Качай исходники (tar) к книге с http://www.piter.com/download/
для книги "UNIX: разработка сетевых приложений".
В tar файле смотри исходник lib/readline.c

HTH

Onanim
()
Ответ на: комментарий от Onanim

Ну не сказать что его алгоритм мне нравится :) Еснно то, что я привел в первом посте, хуже. Но по-моему многочисленные вызовы my_read() для получения одного символа сильно скажутся на производительности. К тому же, ограничение max_len.. Ну в общем суть я понял, спасибо.

P.S. наверное все же реализую вариант с lseek() в файле если прочитано больше, чем нужно.

anonymous
()
Ответ на: комментарий от Onanim

ММ, а что на счет его книги UNIX: взаимодействие процессов ? Имеет ли смысл обе покупать ? А то у меня из бумаги тока справочник да Butenhof Posix threads :(

anonymous
()
Ответ на: комментарий от anonymous

> ММ, а что на счет его книги UNIX: взаимодействие процессов ?
> Имеет ли смысл обе покупать ?
>

Если ты программируешь для Unix - да!
Тем более, что русский перевод продается по вполне доступной цене.
Однако IMHO перевод местами хромает :-(
Кроме того для первого тома уже есть новое, обновленное (третье)
издание на английском.

Onanim
()
Ответ на: комментарий от anonymous

> Ну не сказать что его алгоритм мне нравится :)
> Но по-моему многочисленные вызовы my_read() для
> получения одного символа сильно скажутся на производительности.

Угу. Стивенс так и пишет. И в другом месте таки использует fgets() ;-)

> P.S. наверное все же реализую вариант с lseek() в файле если прочитано больше, чем нужно.

Ну как хочешь :-/ Честно не понимаю, чем stdio в твоем случае хуже.
Когда надо читать по строкам - fgets(), когда блоками - fread().
.
А, еще можешь попробовать твой алгоритм но вместо read/lseek
использовать fgetc/fseek. IMHO все равно быстрее будет.

HTH

Onanim
()
Ответ на: комментарий от Onanim

А как читает fgets() что его реализация будет быстрее моей ? По-моему прочитать блок из файла, найти в нем '\n', поставить туда '\0', сделать strdup, излишки "вернуть" в файл lseek(), если '\n' не нашлось - скопировать в буфер двойного размера, и прочитать еще раз?

В случае fgets() я делаю вызов, если последний символ не новая строка - копирую ее в буфер двойного размера, и в след вызов fgets() переаю ему буфер со смещением, чтобы не затереть сохраненную часть строки?

Ну в принципе звучит несколько проще. Может я и перегнул..

anonymous
()
Ответ на: комментарий от anonymous

> А как читает fgets() что его реализация будет быстрее моей ?
> По-моему прочитать блок из файла, найти в нем '\n', поставить туда
> '\0', сделать strdup, излишки "вернуть" в файл lseek(), если '\n' не
> нашлось - скопировать в буфер двойного размера, и прочитать еще раз?
>

Буферизация. Нет никакого "излишки вернуть в файл lseek" (а то как
бы stdio интересно работал на файлах, для которых seek невозможен,
типа сокетов/пайпов).
stdio читает достаточно большими блоками в свой, внутренний буфер
и уже из него раздает данные fgets, fscanf и прочим fread.

HTH

Onanim
()
Ответ на: комментарий от Onanim

Мм, ну т.е. что то типа Стивенсона получается, тока менее кривое? ;) Ок, наверноe тогда стоит так и сделать

anonymous
()

Если файл - это файл на диске, то (на "типа C")

int fd = open(file) char * ptr = mmap(fd, min(file_size(fd), PTR_MAX)); char * end = memchr(ptr, '\n', min(file_size(fd), PTR_MAX)); char * buffer = malloc(offset - ptr + 1); memcpy(buffer, ptr, offset - ptr); buffer[offset - ptr] = 0;

если поток - man realloc (malloc маленький буфер, заполняем его из потока, (mark) ищем '\n', заменяем на '\0', конец. Если не нашлось - realloc буфер вдвое больше, дополняем из потока, goto mark. Искать, понятное дело, надо не с начала, и с того места, в которое последний раз читали. Стратегию увеличения можно сделать и более сложной, смотря, что нужно).

anonymous
()

Я долго читал тред. Прочитал. Не понял почему забыли getline:
SYNOPSIS
#define _GNU_SOURCE
#include <stdio.h>

ssize_t getline(char **lineptr, size_t *n, FILE *stream);
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);

Но даже не полагаясь на getline, довольно легко делается чтение
строки любой длины через fgets -- надо просто складывать прочитанное,
пока не \n или конец файла.

Casus ★★★★★
()
Ответ на: комментарий от Casus

Да, если не хочется использовать FILE*, тогда буферизацию делать надо самому, это эффективнее сиков, хотя бы тем, что не сбивает с толку механизм readahead.

Casus ★★★★★
()
Ответ на: комментарий от Casus

Даже не знал про эту функцию. Как я понял единственный ее минус - _GNU_SOURCE ? Ну это то, что мне надо. У меня прога и так юзает _GNU_SOURCE

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.