免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: fwizard
打印 上一主题 下一主题

我的程序里边,为什么fwrite没有把数据写到文件里边啊? [复制链接]

论坛徽章:
0
31 [报告]
发表于 2004-04-29 19:57 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

把这个帖子中出现的一些问题归纳了一下。如有不同看法,欢迎继续讨论。

1. 楼主给出的程序是正确的,执行程序能得到预期的结果。这个程序其实出自一本介绍在 Unix 下 C 编程的书(具体叫什么记不得了),以前看到过。

2. 楼主刚开始说产生的文件是“空文件”(真正的结果不是空文件),那只是因为他对文件的检查方式不对。到底文件内容是否为空,不是“看”(指用显示文件内容的命令或者用编辑软件)它能不能显示出东西来,而是要通过查看文件的大小来获知。所谓的“看”,只能使用于文本文件,对非文本文件不适用。

3. fwrite 函数使用二进制方式写文件。例如,一个整数如果用 4 个字节表示,则在文件中一个整数始终占有 4 个字节,不论整数的大小;与此不同,如果是用字符方式写文件,则一个整数在文件中占有的字节数与整数的大小(整型数字的个数)有关(当然还跟规定的格式有关,如果有的话)。

4. 对于二进制文件,它是用来被使用的(如读取、执行等),而不是用来看的(显示它的内容没有实际意义)。比如这个程序产生的二进制文件 datafile,它的作用就是用同样的结构体变量来读取,如上面的 jiutiao2004  给出的程序所示例的那样;这也是检查楼主的程序写 datafile 是否成功的可靠方法。

5. 很多人也已经注意到了,写到 datafile 中的东西并不都是我们所需要的数据,其中还夹杂着一些“垃圾”。产生的原因是由于结构体的“位对齐”造成的(可参见以前的一些这方面的讨论,如这个帖子:http://bbs.chinaunix.net/forum/viewtopic.php?t=68019&highlight=%BD%E1%B9%B9%CC%E5)。本来结构体 record 的大小是 4+9 = 13 个字节,但是由于位对齐的原因,其实际大小是 16。另外,login 字符数组中的字符也并不是全部都是有效字符,这也是产生垃圾的一个原因。垃圾字符的存在不影响 datafile 的使用,不是错误。

6. 关于 fseek 函数。其功能是用来定位文件读写指针。如果文件指的是设备文件,则 fseek 的行为是不确定的;如果文件是一个磁盘文件,则 fseek 函数可以把文件指针指向文件结束符的后面。这时可以从这个位置起写数据,而这之前和原来文件结尾之间的“空隙”部分将用 0 来填充。因此,FH 的担心是多余的。他在上面是这样写的:
>;>; 【逻辑错误】看这里:
>;>; for(i=4;i>;=0;i--)
>;>; 先用i=4调用putrec,对于空文件,fseek会怎样?
>;>; fseek和fwrite的返回码都不判!
>;>; 对于空文件来说,最后写出的文件中应该包含几个记录,谁能说清楚?应该是3条记录而不是5条记录吧?
>;>; 是不是产生空洞好像和系统相关吧?

所以对于空文件,象楼主那样使用fseek也不会有错误。另外,对于这个程序,即使对 fseek 和 fwrite 的返回值不作判断也是可以的,没有什么强有力的理由(比如算法上的要求,这一点要与 fread 函数区别)要求一定这么做,更谈不上是逻辑(算法)上的错误。

论坛徽章:
0
32 [报告]
发表于 2004-04-29 21:09 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

to whyglinux:
1.我没见过哪个文档里面说到fseek可以定位于文件逻辑结束之后的,如果有,麻烦向我推荐一下;如果没有,我不赞成这样使用,即使它被许多环境证明了。因为任何公司都不会保障未公开文档的功能的延续性。
2.关于fseek与fwrite的返回码问题,我仍坚持我的观点,至少可以从fseek的返回码判断是否成功定位于文件逻辑结束之后吧?此外,我觉得fwrite也应该判,至少我的程序里面都判,除非是写log的时候。
3.如果fseek并不能提供所特需的定位功能,那么这个程序是不是有逻辑上的错误呢?我是就此前提论事。

论坛徽章:
0
33 [报告]
发表于 2004-04-30 07:41 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

原帖由 "FH" 发表:
to whyglinux:
1.我没见过哪个文档里面说到fseek可以定位于文件逻辑结束之后的,如果有,麻烦向我推荐一下;如果没有,我不赞成这样使用,即使它被许多环境证明了。因为任何公司都不会保障未公开文档的功能的延续性..........

我查了下 APUE 中文版39页说过 lseek 这样做是可以的,fseek 没有说可以;可以的原因我估计fseek  是对lseek 的上层封装.
其他同意你的观点.
有义务保证自己被调用的代码非常健壮,没有权力要求别人或调用的代码非常健壮.
基于上述的论调,不管是捕捉异常的办法或判断返回码,为了健壮性,程序的运行过程中检查错误是被要求的.

论坛徽章:
0
34 [报告]
发表于 2004-04-30 09:19 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

to windflowers1976:
我也觉得lseek可以的话fseek也应该可以。谢谢。
不过我在几个环境的man中都没有见到对此的说明。

论坛徽章:
0
35 [报告]
发表于 2004-04-30 10:13 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

原帖由 "FH" 发表:
to whyglinux:
1.我没见过哪个文档里面说到fseek可以定位于文件逻辑结束之后的,如果有,麻烦向我推荐一下;如果没有,我不赞成这样使用,即使它被许多环境证明了。因为任何公司都不会保障未公开文档的功能的延续性..........


这里有一篇SunOS的man明确提到了这一点:http://www.cs.biu.ac.il/cgi-bin/man?fseek+3C,还有这里:http://www.opengroup.org/onlinepubs/007908799/xsh/fseek.html。在一般的linux文档中好像是都没有此项说明,但是却能在这种情况下使用,说明还是支持fseek的越过文件尾部写数据的。

论坛徽章:
0
36 [报告]
发表于 2004-04-30 10:36 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

[quote]原帖由 "whyglinux"][/quote 发表:

谢谢。

忽然想到VM好像就是这样写的,结果在Windows文件系统里留下很多碎片,都不能清理。

论坛徽章:
0
37 [报告]
发表于 2004-04-30 10:52 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

碎片产生的原因应该是多次写文件造成的,与 fseek 是否越界(指文件尾部)使用无关。但是可能与 fseek 的频繁使用有关,因为 fseek 会刷新文件缓冲。其实不只是 fseek,还有很多途径可以造成频繁写文件的操作,这应该属于程序员的问题了。我是这么理解的。

论坛徽章:
0
38 [报告]
发表于 2004-04-30 11:06 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

[quote]原帖由 "whyglinux"]碎片产生的原因应该是多次写文件造成的,与 fseek 是否越界(指文件尾部)使用无关。[/quote 发表:

呵呵,不敢苟同。
我觉得这与其产生的缝隙有绝对的关系,Windows认为这就是碎片,不能移动。
顺便说一下,我用的是预分配空间方式。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
39 [报告]
发表于 2004-04-30 11:07 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

这个贴子讨论的人真多。

一个是fseek,一个是fwrite
| 设为精彩回复,大家继续,呵呵

论坛徽章:
0
40 [报告]
发表于 2004-04-30 12:33 |只看该作者

我的程序里边,为什么fwrite没有把数据写到文件里边啊?

  1. /* Copyright (C) 1991, 92, 93, 95, 96, 97 Free Software Foundation, Inc.
  2.    This file is part of the GNU C Library.

  3.    The GNU C Library is free software; you can redistribute it and/or
  4.    modify it under the terms of the GNU Library General Public License as
  5.    published by the Free Software Foundation; either version 2 of the
  6.    License, or (at your option) any later version.

  7.    The GNU C Library is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10.    Library General Public License for more details.

  11.    You should have received a copy of the GNU Library General Public
  12.    License along with the GNU C Library; see the file COPYING.LIB.  If not,
  13.    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14.    Boston, MA 02111-1307, USA.  */

  15. #include <errno.h>;
  16. #include <stdio.h>;


  17. /* Move the file position of STREAM to OFFSET
  18.    bytes from the beginning of the file if WHENCE
  19.    is SEEK_SET, the end of the file is it is SEEK_END,
  20.    or the current position if it is SEEK_CUR.  */
  21. int
  22. fseek (stream, offset, whence)
  23.      register FILE *stream;
  24.      long int offset;
  25.      int whence;
  26. {
  27.   long int o;

  28.   if (!__validfp (stream))
  29.     {
  30.       __set_errno (EINVAL);
  31.       return EOF;
  32.     }

  33.   /* Write out any pending data.  */
  34.   if (stream->;__mode.__write && __flshfp (stream, EOF) == EOF)
  35.     return EOF;

  36.   /* Make sure we know the current offset info.  */
  37.   stream->;__offset = -1;
  38.   if (__stdio_check_offset (stream) == EOF)
  39.     return EOF;

  40.   /* We are moving the file position, so we are no longer at EOF.  */
  41.   stream->;__eof = 0;

  42.   if (stream->;__pushed_back)
  43.     {
  44.       /* Discard the character pushed back by ungetc.  */
  45.       stream->;__bufp = stream->;__pushback_bufp;
  46.       stream->;__pushed_back = 0;
  47.     }

  48.   /* Check the WHENCE argument for validity, and process OFFSET
  49.      into an absolute position in O.  By the end of this switch,
  50.      either we have returned, or O contains an absolute position.  */
  51.   o = offset;
  52.   switch (whence)
  53.     {
  54.     default:
  55.       __set_errno (EINVAL);
  56.       return EOF;

  57.     case SEEK_END:
  58.       /* We don't know where the end of the file is,
  59.          so seek to the position in the file the user asked
  60.          for, and then look where that is.  */
  61.       if (stream->;__io_funcs.__seek == NULL)
  62.         {
  63.           __set_errno (ESPIPE);
  64.           return EOF;
  65.         }
  66.       else
  67.         {
  68.           fpos_t pos = (fpos_t) o;
  69.           if ((*stream->;__io_funcs.__seek)
  70.               (stream->;__cookie, &pos, SEEK_END) < 0)
  71.             {
  72.               if (errno == ESPIPE)
  73.                 stream->;__io_funcs.__seek = NULL;
  74.               return EOF;
  75.             }
  76.           stream->;__offset = pos;
  77.           /* Make O be absolute, rather than
  78.              relative to the end of the file.  */
  79.           o = pos;
  80.         }

  81.       /* Fall through to try an absolute seek.  */

  82.     case SEEK_SET:
  83.       /* Make O be relative to the buffer.  */
  84.       o -= stream->;__target;
  85.       /* Make O be relative to the current position in the buffer.  */
  86.       o -= stream->;__bufp - stream->;__buffer;

  87.       /* Fall through to see if we can do it by
  88.          moving the pointer around in the buffer.  */

  89.     case SEEK_CUR:
  90.       /* If the offset is small enough, we can just
  91.          move the pointer around in the buffer.  */

  92. #if 0        /* Why did I think this would ever work???  */
  93.       if (stream->;__put_limit >; stream->;__buffer)
  94.         {
  95.           /* We are writing.  */
  96.           if (stream->;__bufp + o >;= stream->;__buffer &&
  97.               stream->;__put_limit >; stream->;__bufp + o &&
  98.               stream->;__get_limit >; stream->;__bufp + o)
  99.             {
  100.               /* We have read all the data we will change soon.
  101.                  We can just move the pointer around.  */
  102.               stream->;__bufp += o;
  103.               return 0;
  104.             }
  105.           else
  106.             {
  107.               /* Flush the buffer.  */
  108.               if (__flshfp(stream, EOF) == EOF)
  109.                 return EOF;
  110.             }
  111.         } else
  112. #endif
  113.       if (o < 0 ?
  114.           (-o <= stream->;__bufp - stream->;__buffer) :
  115.           (o <= stream->;__get_limit - stream->;__bufp))
  116.         {
  117.           stream->;__bufp += o;
  118.           return 0;
  119.         }

  120.       /* Turn it into an absolute seek.  */
  121.       o += stream->;__bufp - stream->;__buffer;
  122.       o += stream->;__target;
  123.       break;
  124.     }

  125.   if (o < 0)
  126.     {
  127.       /* Negative file position is meaningless.  */
  128.       __set_errno (EINVAL);
  129.       return -1;
  130.     }

  131.   /* O is now an absolute position, the new target.  */
  132.   stream->;__target = o;

  133.   /* Set bufp and both end pointers to the beginning of the buffer.
  134.      The next i/o will force a call to the input/output room function.  */
  135.   stream->;__bufp
  136.     = stream->;__get_limit = stream->;__put_limit = stream->;__buffer;

  137.   /* Make sure __flshfp doesn't think the put_limit is at the beginning
  138.      of the buffer because of line-buffering magic.  */
  139.   stream->;__linebuf_active = 0;

  140.   /* If there is no seek function, seeks always fail.  */
  141.   if (stream->;__io_funcs.__seek == NULL)
  142.     {
  143.       /* This is preemptive, since we don't actually do the seeking.
  144.          But it makes more sense for fseek to to fail with ESPIPE
  145.          than for the next reading or writing operation to fail
  146.          that way.  */
  147.       __set_errno (ESPIPE);
  148.       return EOF;
  149.     }

  150.   /* Don't actually seek.  The next reading or writing operation
  151.      will force a call to the input or output room function,
  152.      which will move to the target file position before reading or writing.  */
  153.   return 0;
  154. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP