LinuxForum.Fans
Тема

последовательная запись в открытый файл

Автор: shaienn 17 сообщений 1345 просмотров
21.09.2014 17:13 · отредактировано #393328

Добрый день.

Подскажите пожалуйста, как писать в открытый файл разные по размеру объемы данных?
Дело в том, что делаю что-то наподобие:

text
int fd;
int ret;
int i;
char buffer[1024];

fd = open("text.txt", O_RDWR | O_CREAT); for (i=0; i< 10; i++){ ret = write(fd, buffer, (i+1)*10); printf("WR: %d\n", ret); } ret = write(fd, buffer, 10); // Здесь возникает ошибка printf("WR: %d\n", ret); close(fd);

Когда объем данных увеличивается, проблем нет, все пишется. Но на последнем шаге, ret == -1, ошибка EINVAL. Как побороть?

Спасибо.

21.09.2014 17:31 #393331

Попробуйте для начала в open() указать 3-й аргумент, mode, потом посмотрим.

Пётр.

22.09.2014 02:13 #393388

"shaienn" написал:
Как побороть?
используйте fwrite(3)/fopen(3) и т.д.
22.09.2014 02:21 #393389
"Peter" написал:
Попробуйте для начала в open() указать 3-й аргумент
зачем? Оно 0666. Проблема не в этом.
"shaienn" написал:
ошибка EINVAL.

EINVAL The filesystem does not support the O_DIRECT flag. See NOTES for more information.
22.09.2014 09:00 #393399

Дело в том, что компилятор требует, чтобы при указании флага O_CREAT был задан и аргумент mode.
А проблема, конечно, не в правах как таковых. Более подробное описание этой ошибки в errno-base.h.


Пётр.

22.09.2014 10:19 #393404

Сейчас посмотрел на другом компьютере, там не потребовалось указывать mode.
Но всё же правильно так:

text

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(){
int i,fd,n,m;
char buf[1024];
  fd=open("file.txt",O_RDWR|O_CREAT|O_TRUNC,0644);n=0;
  for(i=0;i<10;i++){memset(buf+n,65+i,(i+1)*10);n=n+(i+1)*10;buf[n-1]='\n';}
  m=0;for(i=0;i<10;i++){n=write(fd,buf+m,(i+1)*10);m=m+(i+1)*10;
  if(n==(i+1)*10)fprintf(stdout,"wr %d %d %d\n",i,m,n);
  if(n==-1)fprintf(stdout,"n wr %d %d %s\n",i,errno,strerror(errno));}
  n=write(fd,buf,10);fprintf(stdout,"wr %d\n",n);
  close(fd);
  return 0;
}

Пётр.

22.09.2014 15:43 #393442

"Peter" написал:
Дело в том, что компилятор требует, чтобы при указании флага O_CREAT был задан и аргумент mode.
что за бред? Что за компилятор?

"Peter" написал:
0644
говорю же, 0666, а 0644 оно будет после &~UMASK, если UMASK=022.
22.09.2014 15:53 · отредактировано #393446

drBatty написал:
[quote="Peter"]Дело в том, что компилятор требует, чтобы при указании флага O_CREAT был задан и аргумент mode.
что за бред? Что за компилятор?

"Peter" написал:
0644
говорю же, 0666, а 0644 оно будет после &~UMASK, если UMASK=022.[/quote]
Вчера в Ubuntu-14.04 я запустил вариант автора и компилятор gcc сказал,
что при задании O_CREAT необходим и 3-й аргумент.

Сегодня попробовал в другой системе, фактически это Debian stable,
там 3-й аргумент не требовался, но без него программа не работает с O_TRUNC,
если файл уже существует.
Я не выяснял, какой там umask, но с mode=0644 права у файла тоже 644.

Пётр.
23.09.2014 04:06 #393496

"Peter" написал:
Вчера в Ubuntu-14.04 я запустил вариант автора и компилятор gcc сказал,
что при задании O_CREAT необходим и 3-й аргумент.
не может компилятор такого сказать. Он вообще не в курсе про ваши функции.

Зачем вы вообще слушаете компилятор, и собираете ПО в таком кривом дистрибутиве? Читайте ман:
text

OPEN(2)                               Linux Programmer's Manual                               OPEN(2)

NAME open, openat, creat - open and possibly create a file

SYNOPSIS #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>

int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);

наверное вы забыли включить какой-то *.h файл.

"Peter" написал:
там 3-й аргумент не требовался, но без него программа не работает с O_TRUNC,
если файл уже существует.
что значит "не работает"? Какой код ошибки?

"Peter" написал:
Я не выяснял, какой там umask, но с mode=0644 права у файла тоже 644.

Пётр
Пётр, может вы почитаете наконец, что такое umask и mode?

PS:
когда я вижу такой код
text
  fd=open("file.txt",O_RDWR|O_CREAT|O_TRUNC,0644);n=0;
  for(i=0;i<10;i++){memset(buf+n,65+i,(i+1)*10);n=n+(i+1)*10;buf[n-1]='\n';}
  m=0;for(i=0;i<10;i++){n=write(fd,buf+m,(i+1)*10);m=m+(i+1)*10;
  if(n==(i+1)*10)fprintf(stdout,"wr %d %d %d\n",i,m,n);
  if(n==-1)fprintf(stdout,"n wr %d %d %s\n",i,errno,strerror(errno));}
  n=write(fd,buf,10);fprintf(stdout,"wr %d\n",n);

хочется взять, и уе…


короче спасибо, проблевался.

23.09.2014 09:18 · отредактировано #393504

Нет, насколько сейчас помню, все эти три файла были включены.
Код ошибки не помню, а сообщение при запуске программы при уже
существующем файле - Bad file descriptor, но это, кажется,
при вызове write().

Мне нравится писать плотно, чтобы на экране или на листе бумаги
был виден сразу большой кусок. Я и для перфокарт для программ на PL/1
заполнял бланк полностью, а когда стал работать в дисплейном зале,
то написал программу, которая из текста на PL/1 удаляла лишние пробелы
и получался ласкающий глаз прямоугольник. Я там видел ещё одного
человека с такими же распечатками. И вообще компилятору всё равно.

А сейчас, если надо, можно воспользоваться программой indent.
Я составил команду её вызова с дополнительными опциями.

Что такое umask и mode, я конечно, читал. Иногда я явно использую umask.

Вот эта команда для вызова indent, параметр - имя файла в форме name.ext.

text

#!/bin/bash

nam=`echo $1 |cut -d "." -f 1` sff=`echo $1 |cut -d "." -f 2` mv -f $1 ${nam}_ori.$sff indent -kr -brf -ci0 -l80 -nbfda -cdw ${nam}_ori.$sff -o $1

Пётр.

23.09.2014 23:56 #393601

drBatty написал:
[quote="Peter"]Дело в том, что компилятор требует, чтобы при указании флага O_CREAT был задан и аргумент mode.
что за бред? Что за компилятор?
[/quote]
Вот его сообщения при попытке использовать флаг O_CREAT без mode:
[console]
In file included from /usr/include/fcntl.h:279:0,
from ch_wr.c:5:
In function ‘open’,
inlined from ‘main’ at ch_wr.c:10:4:
/usr/include/x86_64-linux-gnu/bits/fcntl2.h:50:24: error: call to ‘__open_missing_mode’ declared with attribute error: open with O_CREAT in second argument needs 3 arguments
__open_missing_mode ();
[/console]

[console]
Source: gcc-defaults (1.124ubuntu6)
VerSource: gcc-defaults (1.124ubuntu6)
[/console]

Пётр.
24.09.2014 03:50 #393608
"Peter" написал:
Мне нравится писать плотно
про читателей вы подумали? Нет? Ну тогда и не показывайте этого никому.

Это ваше УГ читать невозможно, особенно на этом форуме(тут нет подсветки).

"Peter" написал:
и получался ласкающий глаз прямоугольник.

https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%84%D1%83%D1%81%D0%BA%D0%B0%D1%86%D0%B8%D1%8F

используется в JavaScript, C#, и прочем УГ.


ну вот вам рабочий код:

text
/* use open(2) */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* use fprintf(3) */ #include <stdio.h>

/* use close(2) */ #include <unistd.h>

int main() { int fd = open("./test", O_CREAT); if(fd<0) { fprintf(stderr, "Can't open file\n"); return 1; } close(fd); return 0; }

нормально всё собирается в
[console]$ gcc --version
gcc (GCC) 4.8.3
Copyright (C) 2013 Free Software Foundation, Inc.
Это свободно распространяемое программное обеспечение. Условия копирования
приведены в исходных текстах. Без гарантии каких-либо качеств, включая
коммерческую ценность и применимость для каких-либо целей.
[/console]

24.09.2014 03:52 #393609

да, новый файл вот такой получается:
[console]$ ls -l test
---------- 1 drb users 0 сен 24 03:46 test
[/console]
т.ч. ладно, уломали, mode тут нужно. Раз вы файл создаёте, то оно принимается равным 0000, о чём вас бубунтовская версия компилятора и предупреждает.

24.09.2014 04:05 · отредактировано #393610

да, посмотрел свой /usr/include/fcntl.h
там

text
/* Open FILE and return a new file descriptor for it, or -1 on error.
   OFLAG determines the type of access used.  If O_CREAT is on OFLAG,
   the third argument is taken as a `mode_t', the mode of the created file.

This function is a cancellation point and therefore not marked with __THROW. */ #ifndef __USE_FILE_OFFSET64 extern int open (const char *__file, int __oflag, ...) __nonnull ((1)); #else # ifdef __REDIRECT extern int __REDIRECT (open, (const char *__file, int __oflag, ...), open64) __nonnull ((1)); # else # define open open64 # endif #endif #ifdef __USE_LARGEFILE64 extern int open64 (const char *__file, int __oflag, ...) __nonnull ((1)); #endif

#ifdef __USE_ATFILE +-- 9 строк: Similar to `open' but a relative path name is interpreted relative to------------------------------ # ifndef __USE_FILE_OFFSET64 extern int openat (int __fd, const char *__file, int __oflag, ...) __nonnull ((2)); # else # ifdef __REDIRECT extern int __REDIRECT (openat, (int __fd, const char *__file, int __oflag, · · · · ...), openat64) __nonnull ((2)); # else # define openat openat64 # endif # endif

мораль: на добыло юзать fopen(3), как я с самого начала и предлагал.

24.09.2014 09:10 #393625
drBatty написал:
да, новый файл вот такой получается:
[console]$ ls -l test
---------- 1 drb users 0 сен 24 03:46 test
[/console]
т.ч. ладно, уломали, mode тут нужно. Раз вы файл создаёте, то оно принимается равным 0000, о чём вас бубунтовская версия компилятора и предупреждает.

Сейчас ещё раз запустил там, где компилируется без mode, у файла оказались права 0250.
Я не стал обрабатывать свой текст программой indent, т.к. она короткая и чтобы было легче
скопировать. И всё равно она тестовая.
Если вывод делается неформатированный, то лучше open и write,
т.к. и проще и всё равно в конечном счёте работает через них.

Пётр.

24.09.2014 11:08 #393632
"Peter" написал:
Сейчас ещё раз запустил там, где компилируется без mode, у файла оказались права 0250.
похоже у вас всё равно три параметра, но там многоточие из ansi C, и вместо mode у вас попадает мусор. А у меня именно два параметра. Подозреваю, что это связано с тем, что я пробовал на нетбуке, а тут у меня 32х битная ОС. Проверять на 64х битном компе лениво.

В любом случае, O_CREAT это просто целая константа, от неё ничего не зависит (без O_CREAT open(2) игнорирует третий параметр).

"Peter" написал:
Если вывод делается неформатированный, то лучше open и write,
т.к. и проще и всё равно в конечном счёте работает через них.

ЩИТО? Что значит "вывод неформатированный"?

И да, в конечном счёте всё делается ATA командами, что вы их не юзаете? Оно жеж "проще", не?

А вот я рекомендую юзать самый высокоуровневый интерфейс, в C98 это fopen(3), а open(2) нужно для чего-то такого низкоурвнего, которое совершенно непереносимо и его сложно поддерживать. Вы сами видите, что поведение open(2) разное в разных системах, вам так нужна лишняя головная боль? Юзали-бы стандартную (прописанную в стандарте) fopen(3), и проблемы-бы не было.

PS:

"Peter" написал:
Я не стал обрабатывать свой текст программой indent, т.к. она короткая и чтобы было легче
скопировать. И всё равно она тестовая.

программа без отступов, это как неграмотный русский текст. Мне плевать на _вашу_ грамотность, это не имеет значения. Читать тяжело! И остаётся вопрос: зачем вы это запостили? Ведь для ТСа это будет ещё сложнее, разве нет? У него тоже проблемы со стилем, но он-то начинающий, ему можно. Т.ч. не обижайтесь пожалуйста, я не говорю, что "у вас плохой стиль", не потому что он плохой, а потому, что меня это не волнует. Плохо то, что ваш код сложно читать, особенно на форуме, а не в уютном редакторе (который к тому-же может исправить ваш любимый стиль на мой любимый стиль, что-бы всем было хорошо).

Ещё раз: я не собираюсь начинать полемику "какой стиль лучше и сколько пробелов должно быть в инденте!!!!", это не имеет для меня значения. Просто не волнует. Кого волнует, может идти на ЛОР, там полно тем про это. Но раз тут подсветки нет, то хоть отступы делайте, что-бы было понятнее.

Для сравнения:

Код с отступами:

Показать
text

#!/bin/sed -rf

# сохранение строки h

:begin_loop # p # удаление обычного начала s/^[^'"#\]+(.*)/\1/ t begin_loop # удаление экранированных символов s/^\\.// t begin_loop # удаление закавыченного блока s/^'[^']*'// t begin_loop s/^'.*// T lq # незакрытый блок кавычек, необходима подгрузка ${ x b end } n H s/^/'/ t begin_loop :lq # удаление экранированной кавычки внутри закавыченного блока s/^"[^"]*\\"/"/ t begin_loop # удаление закавыченного блока s/^"[^"]*"// t begin_loop s/^".*// T lq2 ${ x b end } n H s/^/"/ t begin_loop :lq2 /^\#/{ # теперь строка начинается с # H x s/^(.*)(\#[^\n]*)\n\2$/\1/ b end } # а коммента и нету x

:end # s/.*/\x1b[32m'&'\x1b[0m/

А вот как пишет ТС:

Показать
text
#!/bin/sed -rf
h
:b
s/^[^'"#\]+(.*)/\1/
tb
s/^\\.//
tb
s/^'[^']*'//
tb
s/^'.*//
Tl
${
x
be
}
n
H
s/^/'/
tb
:l
s/^"[^"]*\\"/"/
tb
s/^"[^"]*"//
tb
s/^".*//
T lq2
${
x
be
}
n
H
s/^/"/
tb
:l2
/^\#/{
H
x
s/^(.*)(\#[^\n]*)\n\2$/\1/
be
}
x
:e

А вот ваш стиль:

text
#!/bin/sed -rf
h;:b;s/^[^'"#\]+(.*)/\1/;tb;s/^\\.//;tb
s/^'[^']*'//;tb;s/^'.*//;Tl;${;x;be;}
n;H;s/^/'/;tb;:l;;s/^"[^"]*\\"/"/;tb;
s/^"[^"]*"//;tb;s/^".*//;Tlq2;${;x;be
};n;H;s/^/"/;tb;:l2;/^\#/{;H;x;
s/^(.*)(\#[^\n]*)\n\2$/\1/;be;};x;:e

теперь вы понимаете, почему меня тошнит от такого?

24.09.2014 11:48 #393639

"Неформатированный вывод" - вывод некоего количества байтов, как в функции write(),
а форматированный я имел в виду который делает fprintf().
fwrite() я никогда не пользуюсь, сейчас посмотрел, что это и подумал, что open()/write()
гораздо удобнее. Если в точности соблюдать синтаксис, то и работать будет
везде одинаково.

Я как раз для ТС и поместил это, у него же не работало. А разбить на строки такую
короткую программу ему бы труда не составило. Тем более, что там часть можно
просто выбросить, т.к. она только для наглядности. Главное, что надо было
использовать 3-й аргумент в open().

Пётр.

Войдите или зарегистрируйтесь, чтобы ответить.