免费注册 查看新帖 |

Chinaunix

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

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

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

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

原帖由 "FH" 发表:

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


FH 多次提到“缝隙”这个概念,认为文件中真的存在着这么一个空白区域,真的是这样吗?

缝隙这个概念是在使用 fseek 定位文件指针、并且文件指针位置越过了文件结尾时产生的一个概念,此刻它指的是目前文件指针位置和原来文件结束位置之间的这片区域。注意,此时磁盘文件中并没有这样的一片区域,因为你还没有进行写文件的操作。

如果此时进行一个写文件的操作,根据 fseek 函数的说明,这块所谓的“缝隙”区域会用 0 来填充,然后随同要写的数据一起送到文件缓冲(即真正出现在文件中的内容)。从写文件开始起,“缝隙”这个概念已经不存在了,在磁盘文件中更不会有上述“缝隙”区域的存在。

为了说明这个问题,写了下面两个程序。程序功能分别是写一个100字节的文件(除了最后一个字节为字符 'a' 外,文件的其它内容为 0),区别就是一个不用 fseek,一个用fseek。特别请 FH 检验一下两种方式产生的两个文件有什么不同,fseek 带来的“缝隙”到底对最终文件有无影响。至少,我看不出这两个文件(tst1、tst2)有什么不同。

  1. #include <stdio.h>;

  2. #if 1 // <= change the 1 here to 0 to compile program 2

  3. // program 1: without using fseek()
  4. int main()
  5. {
  6.   FILE *fp;
  7.   char c[99];
  8.   int i;
  9.   for (i=0; i<99; i++) {
  10.     c[i] = 0;
  11.   }
  12.   fp = fopen("tst1", "w");
  13.   fwrite(c, 1, 99, fp);
  14.   fwrite("a", 1, 1, fp);
  15.   fclose(fp);
  16. }

  17. #else

  18. // program 2: with using fseek()
  19. int main()
  20. {
  21.   FILE *fp;
  22.   fp = fopen("tst2", "w");
  23.   fseek(fp, 100-1, 0);
  24.   fwrite("a", 1, 1, fp);
  25.   fclose(fp);
  26. }

  27. #endif
复制代码
fseek 函数的源代码

另外,上面windflowers1976贴出的 fseek 函数的源代码说明文件指针越过文件前面是非法的,但是指到文件结尾之后却没有问题。但是 fseek 的源代码还不能说明此时的 fwrite 或者 fread 函数是怎样处理这一情况的,关于这一点,要到 fwrite 和 fread 的代码中去查找吧。

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

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

/* Don't actually seek.  The next reading or writing operation
     will force a call to the input or output room function,
     which will move to the target file position before reading or writing.  */

  1. /* Copyright (C) 1991, 92, 93, 94, 96, 97, 98 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. #include <string.h>;


  18. /* Write NMEMB chunks of SIZE bytes each from PTR onto STREAM.  */
  19. size_t
  20. fwrite (ptr, size, nmemb, stream)
  21.      const void *ptr;
  22.      size_t size;
  23.      size_t nmemb;
  24.      register FILE *stream;
  25. {
  26.   register const unsigned char *p = (const unsigned char *) ptr;
  27.   register size_t to_write = size * nmemb;
  28.   register size_t written = 0;
  29.   int newlinep;
  30.   size_t buffer_space;
  31.   int default_func;

  32.   if (!__validfp (stream) || !stream->;__mode.__write)
  33.     {
  34.       __set_errno (EINVAL);
  35.       return 0;
  36.     }

  37.   if (ferror (stream))
  38.     return 0;
  39.   if (p == NULL || to_write == 0)
  40.     return 0;

  41.   if (!stream->;__seen || stream->;__put_limit == stream->;__buffer)
  42.     {
  43.       /* This stream has never been seen before.
  44.          Calling __flshfp will give it a buffer
  45.          and I/O functions if it needs them.  */
  46.       if (__flshfp (stream, *p++) == EOF)
  47.         return 0;
  48.       if (--to_write == 0)
  49.         return 1;
  50.       else
  51.         ++written;
  52.     }

  53.   default_func
  54.     = stream->;__room_funcs.__output == __default_room_functions.__output;

  55.   {
  56.     int save = errno;

  57.     if (__stdio_check_offset (stream) == EOF && errno != ESPIPE)
  58.       {
  59.         stream->;__error = 1;
  60.         goto done;
  61.       }

  62.     __set_errno (save);
  63.   }

  64.   if (stream->;__buffer == NULL && default_func &&
  65.       stream->;__offset == stream->;__target)
  66.   write_through:
  67.     /* This is an unbuffered stream using the standard output
  68.        buffer-flushing function, so we just do a straight write.  */
  69.     {
  70.       int count = (stream->;__io_funcs.__write == NULL ? to_write :
  71.                    (*stream->;__io_funcs.__write) (stream->;__cookie,
  72.                                                   (const char *) p,
  73.                                                   to_write));
  74.       if (count >; 0)
  75.         {
  76.           written += count;
  77.           if (stream->;__offset != -1)
  78.             {
  79.               stream->;__offset += count;
  80.               stream->;__target = stream->;__offset;
  81.             }
  82.           to_write -= count;
  83.           p += count;
  84.         }
  85.       else
  86.         stream->;__error = 1;
  87.       goto done;
  88.     }

  89.   /* We ignore the end pointer here since we want to find out how much space
  90.      is really in the buffer, even for a line-buffered stream.  */
  91.   buffer_space = stream->;__bufsize - (stream->;__bufp - stream->;__buffer);

  92.   newlinep = (stream->;__linebuf &&
  93.               memchr ((const void *) p, '\n', to_write) != NULL);

  94.   if (newlinep && stream->;__bufp == stream->;__buffer &&
  95.       stream->;__offset == stream->;__target)
  96.     /* The buffer's empty, and we want to write our data
  97.        out soon anyway, so just write it straight out.  */
  98.     goto write_through;

  99.   if (stream->;__bufsize == 0 && !default_func)
  100.     {
  101.       /* No buffer, and a special function.
  102.          We can't do much better than putc.  */
  103.       while (to_write-- >; 0)
  104.         {
  105.           if (__flshfp (stream, *p++) == EOF)
  106.             break;
  107.           else
  108.             ++written;
  109.         }
  110.     }
  111.   else if (!default_func || buffer_space >;= to_write)
  112.     {
  113.       /* There is enough room in the buffer for everything we want to write
  114.          or the user has specified his own output buffer-flushing/expanding
  115.          function.  */
  116.     fill_buffer:
  117.       while (to_write >; 0)
  118.         {
  119.           register size_t n = to_write;

  120.           if (n >; buffer_space)
  121.             n = buffer_space;

  122.           buffer_space -= n;

  123.           written += n;
  124.           to_write -= n;

  125.           if (n < 20)
  126.             while (n-- >; 0)
  127.               *stream->;__bufp++ = *p++;
  128.           else
  129.             {
  130.               memcpy ((void *) stream->;__bufp, (void *) p, n);
  131.               stream->;__bufp += n;
  132.               p += n;
  133.             }

  134.           if (to_write == 0)
  135.             /* Done writing.  */
  136.             break;
  137.           else if (buffer_space == 0)
  138.             {
  139.               /* We have filled the buffer, so flush it.  */
  140.               if (fflush (stream) == EOF)
  141.                 break;

  142.               /* Reset our record of the space available in the buffer,
  143.                  since we have just flushed it.  */
  144.             check_space:
  145.               buffer_space = (stream->;__bufsize -
  146.                               (stream->;__bufp - stream->;__buffer));
  147.               if (buffer_space == 0)
  148.                 {
  149.                   /* With a custom output-room function, flushing might
  150.                      not create any buffer space.  Try writing a single
  151.                      character to create the space.  */
  152.                   if (__flshfp (stream, *p++) == EOF)
  153.                     goto done;
  154.                   ++written;
  155.                   --to_write;
  156.                   goto check_space;
  157.                 }
  158.             }
  159.         }

  160.       /* We have written all the data into the buffer.  If we are
  161.          line-buffered and just put a newline in the buffer, flush now to
  162.          make sure it gets out.  */
  163.       if (newlinep)
  164.         fflush (stream);
  165.     }
  166.   else
  167.     {
  168.       /* It won't all fit in the buffer.  */

  169.       if (stream->;__bufp != stream->;__buffer)
  170.         {
  171.           /* There are characters in the buffer.  Flush them.  */
  172.           if (__flshfp (stream, EOF) == EOF)
  173.             goto done;
  174.         }

  175.       /* The buffer has been flushed.
  176.          Now either fill it or write directly.  */

  177.       buffer_space = stream->;__bufsize - (stream->;__bufp - stream->;__buffer);

  178.       if (stream->;__offset == stream->;__target &&
  179.           (buffer_space < to_write || newlinep))
  180.         /* What we have to write is bigger than the buffer,
  181.            or it contains a newline and we're line-buffered,
  182.            so write it out.  */
  183.         goto write_through;
  184.       else
  185.         /* It will fit in the buffer.  */
  186.         goto fill_buffer;
  187.     }

  188. done:;
  189.   return (size_t) written / size;
  190. }

  191. weak_alias (fwrite, fwrite_unlocked)
复制代码

呵呵,内核代码有人看啊.

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

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

fseek允许设置文件位置超过文件的当前文件尾,如果之后在此新文件位置写入了数据,则后续从原文件尾新新写入的数据之间的空隙中读出的字节将用0填充直至次空隙写入实际的数据为止,下面给出的程序说明用fseek定位文件文件位置超过文件尾的两种情形。第一种是以非添加方式写数据超过文件尾,此时在当前文件尾和新写入的数据之间将行成所谓的“空洞”。第二种是以添加方式写数据,此时尽管可以用fseek定位文件当前位置超过文件尾,但是写该文件时,文件的当前位置被忽略,所有的数据都添加在文件尾并且文件当前位置被重新定位到新的文件尾
#include <stdio.h>;
#include <stdlib.h>;
#include "err_exit.h"

char buf[132];

int main(int argc,char *argv[])
{
  FILE *fd;
  fpos_t pos;
  if(argc != 2){
     fprintf(stderr,"Usage: %s mode \n",argv[0]);
     exit(EXIT_FAILURE);
   }
   
   if(argv[1][0]!='a'){
   if  ((fd = fopen("test_file","w+")==NULL)
   err_exit("fopen failed";
   }
   else{
     if((fd = fopen("test_file","a+")==NULL)
     err_exit("fopen failed";
     }
     
     
   fputs("0123456789",fd);
   fputs("ABCDEFGHIJ",fd);
   
   fseek(fd,0,SEEK_END);
   fgetpos(fd,&pos);
   printf("current file en position is %ld\n",pos);
   
   fseek(fd,30,SEEK_END);
   
   fgetpos(fd,&pos);
   printf("Now we call fseek(fd,30,SEEK_END)\n";
   printf("Current file position is %ld \n",pos);
   
   fputs("abcdefg",fd);
   printf("Now we write %c %s %c\n",'\"',"abcdefg",'\"');
   
   fgetpos(fd,&pos);
   printf("current position of file end is %ld\n",pos);
   fclose(fd);
}


运行示例:
# t13 a+
current file en position is 20
Now we call fseek(fd,30,SEEK_END)
Current file position is 50
Now we write " abcefg "
current position of file end is 57
current position of file end is 27
# od -c test_file
0000000   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
0000020   G   H   I   J   a   b   c   d   e   f   g
0000033


# t13 w+
current file en position is 20
Now we call fseek(fd,30,SEEK_END)
Current file position is 50
Now we write " abcefg "
current position of file end is 57
# od -c test_file
0000000   0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
0000020   G   H   I   J  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000060  \0  \0   a   b   c   d   e   f   g
0000071


几点说明:
   1。我这上面的程序基本上都是来源于unix程序设计教程这本书,自认为对于有一定c和c++编程基础又刚接触unix编程时的一本好书。当然如果在瘟下比较牛的话,可能也不需要,我是刚参加工作,理论有实践还比较差
   2。对于前面程序涉及的东西我想几位的解释已经让我明白的差不多了,先谢谢大家的热心帮助。
   3。关于大家后面的讨论我这里照样摘录了一个程序,大家运行测试一下,就知道里边包含的意思了
   4。对这个程序我运行的结果和书上给出的结果稍有出入,欢迎大家测试和讨论。
其中第一个红色行是对应行的书上给的结果
第二个红行是我运行出来的,书上没有。

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

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

1

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

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

to whyglinux:
缝隙(gap)引自你提供的man文档。缝隙这一概念显然是逻辑上的而不是物理上的,这一点不用讨论。
我说的是缝隙给Windows FAT32文件系统造成的假象,即文件碎片问题。
我的VMDK文件存在很多碎片,怎么copy都不能消除,也不能被碎片整理工具消除。

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

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

那你看看文件的属性是否是系统属性,这样的文件不允许移动。比如Windows下那个大大的临时文件好像就是这样的。试试把文件的系统属性去掉,再用碎片整理。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP