|
[Original]
[Print]
[Top]
|
方法1.
sprintf(cmd_line,"cp %s %s",file_s,file_o);
system(cmd_line);
方法2.打开第一个文一点一点的读出来直接写到另一个件里,就可以了。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
回答问题,精神可嘉,但是不知道就不要乱说
方法1.的语法是错误的 int system(const char *string);
方法2.也有问题。
正确做法是:
1. 打开两个文件A (O_RDONLY), B(O_WRONLY|O_CREAT),
2. 准备一个buffer(系统的cp命令用的是一个4k长度的buffer),
3. 从A读,写入B.
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
打开两个文件A (O_RDONLY), B(O_WRONLY|O_CREAT,
打开件a(O_RDONLY)有这样的函数??????????
你不会也不要乱讲。
其实我告诉的只是一个方法。
用system的确可以实现拷。第二个你说的还是从一个文件里面读出写到另一个件里和我的有什么不同吗。
只不过你说的更祥细一点。不过我认为从一个文件里面读数据当然要用buffer太显然的问题就不要讲了吧。
你是不是还要告诉人家。定义buffer用char buffer[4*1024],等等。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
火气不要太大,错了就要虚心一点,也没什么大不了的.
Atu的意思显然是说用open来打开文件A和B,open的第二个参数(flags)分别使用O_RDONLY和O_WRONLY|O_CREAT.你要是用过open的话就不可能误解.
至于第二个问题,你说"一行一行的读出来",我想Atu是针对这个的吧.只有文本文件才有行的概念,而cp所处理的显然不仅仅是文本文件.
|
|
----
我只是个coder
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
> 你不会也不要乱讲。
我不会的不会乱说的,至少我在这里回答问题,基本都是实际验证过的。
就象刚才说的缓冲区长度4k,我就是实际检查了cp所使用的缓冲区的长度,
缓冲区长度关系到文件拷贝的性能,我也没这个经验,
所以,实际查看了我的机器上/bin/cp使用的缓冲区长度,
说你不对,不委屈你,
你告诉人家一行一行复制,是打算让人家用fgets()去读源文件?
同样是buffer,是按行读,还是按长度读,是绝对的不同,这个不需要我解释吧
至于O_RDONLY,O_WRONLY,O_CREAT,我只是把cp调用open的标志抄过来了,
给别人一个参考而已,
如果你看到这些标记还不知道它的含义,只能说你太菜了,或者是成心装糊涂
顺便这里补充一下吧,cp在打开文件的时候,实际还有一个O_LARGEFILE选项,
如果程序不准备处理大于2G文件的话,这个选项可以不用的。
> 你是不是还要告诉人家。定义buffer用char buffer[4*1024],等等。
说详细一点总不是坏事吧?
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我不明白的是,你可以a(O_RDONLY)
我为什么就不可以system("cp %s %s",file_s,file_o);
我这句有语法错误.你的a(O_RDONLY)难道没有语法错误?????????
其实我们都是在告诉一种法方法.没必要扣那么细吧.
char cmdline[256];
sprintf(cmdline,"cp %s %s",file_s,file_o);//file_o,file_s是存放源文件名,和目标文件名的字符串的首址
system(cmdline);
这样总可以了吧
我希望你能明白我也是在尽力的帮助别人,没有乱讲.我说的方法也都是经过验证的
fgets我还真没想用这个函数,
我是想用fopen打开一个文件然后用fread去读然后用fwrite去写一行一行是写得有点不好,因为二进制文件不是以行的.我表达欠妥.
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
int src = open ("srcfile", O_RDONLY);
int dst = open ("dstfile", O_RDWR|O_TRUNC|O_CREAT, 0666);
struct stat fst;
fstat (src, &fst);
off_t offset = 0;
sendfile (dst, src, &offset, fst.st_size);
|
|
----
mount -o sync,dirsync
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
其实大家都是讲实现的方法而已, 没必要那么细. 至少smalllight的第1个方法是可行的.
Atu说话有点让人下不来吧? 呵呵~~~
|
|
----
喜欢在海里游的鱼儿。。。。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
|
很对。最重要的是方向上的提示,细节的东西可以自己去解决。其实只要有人告诉我一个是system-cp,一个是read-write就足够了。不过Atu的敬业和细致还是值得称道的。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
在solaris下是可以处理两个磁盘文件的,linux下好像不行,我试不通,不过文档也没有否定,怕是还没完全实现罢
Either or both of these file descriptors may refer to a socket (but see below)
Presently the descriptor from which data is read cannot correspond to a socket, it must correspond to a file which
supports mmap()-like operations.
|
|
----
mount -o sync,dirsync
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
>目前如果output fd不是socket的话,Linux下sendfile会失败
>EINVAL
是否是内核版本问题?
我测试,似乎是可用的,代码如下(简陋了一点)
内核版本:2.4.21-20
$ cat a.c
#include <sys/sendfile.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int s = open("/boot/vmlinuz-2.4.21-20.EL", O_RDONLY);
int d = open("output", O_WRONLY | O_CREAT, 0600);
off_t off = 0;
ssize_t size = sendfile(d, s, &off, 10000000);
printf("size = %d, off = %d
", size, off);
}
$ ./a
size = 1243768, off = 1243768
$ md5sum output /boot/vmlinuz-2.4.21-20.EL
a7a6a1d88660615f357fef276140ddd7 output
a7a6a1d88660615f357fef276140ddd7 /boot/vmlinuz-2.4.21-20.EL
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
俺没测试成功。于是写了个函数来模仿sendfile.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
ssize_t sendfile_mmap(int out_fd, int in_fd, off_t *offset, size_t count)
{
char *in_data_ptr;
int n;
in_data_ptr = mmap(NULL, count, PROT_READ, MAP_PRIVATE, in_fd, 0);
if(in_data_ptr == NULL)
{
return -1;
}
n = write(out_fd, in_data_ptr, count);
munmap(in_data_ptr, count);
*offset = n;
return n;
}
int main(int argc, char *argv[])
{
int in_fd, out_fd;
size_t datalen;
off_t of;
in_fd = open("/home/phus/downloads/1.jpg", O_RDONLY);
out_fd = open("/home/phus/downloads/2.jpg", O_RDWR, 0644);
datalen = lseek(in_fd, 0L, 2);
sendfile_mmap(out_fd, in_fd, &of, datalen);
printf("::%ld
", of);
close(in_fd);
close(out_fd);
return 0;
}
phus@localhost /home/phus/downloads $ md5sum 1.jpg 2.jpg
d6aec64f998b5290566ac063645d7287 1.jpg
d6aec64f998b5290566ac063645d7287 2.jpg
测试可行
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
本来想用两次mmap然后在memcpy的。
但是用lseek出来的空洞文件不能mmap, 当然是bus error了。
不知有没有解决办法。
用strace跟了一下dd if=/dev/zero of=./3.jpf bs=1024, 似乎dd也是用write, 不过说不定有什么库函数的封装.
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
>>用strace跟了一下dd if=/dev/zero of=./3.jpf bs=1024, 似乎dd也是用write, 不过说不定有什么库函数的封装.
猜想这里应该是设备驱动层的write接口,而不是普通文件的write
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
呵呵, 应该是这样的。
不过我的意思是说:"用户程序生成文件的方法就只有write了吗?"
有没有其它办法, 比如系统调用(这个不太可能), 封装库好的函数(似乎也没有).
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
|
是啊,在2.4内核下就可以,看了一下,2.4的sys_sendfile实现在mm/filemap.c,2.6的sys_sendfile实现在fs/read_write.c,而且实现有些不同,关键可能在2.4的common_sendfile和2.6的do_sendfile,其中有几处返回 EINVAL。或许是2.6的一个bug,熟悉内核的朋友可否解释一下
|
|
----
mount -o sync,dirsync
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
怀疑do_sendfile里的这一行
retval = security_file_permission (out_file, MAY_WRITE);
|
|
----
mount -o sync,dirsync
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
有没有可能是glibc封装的呢
不知Atu和lonelyflyer有没有用strace看过?
二位用的是哪一个2.4的系统?
我总觉得有点奇怪
这么好的特性,为什么不带入2.6呢?
|
|
----
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我把strace结果贴给你看吧
sendfile确实是一个专门的系统调用。
OS: redhat-release-3AS-7.3
$ strace ./a >/dev/null
execve("./a", ["./a"], [/* 28 vars */]) = 0
uname({sys="Linux", node="linux", ...}) = 0
brk(0) = 0x86da000
open("/etc/ld.so.preload", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=17, ...}) = 0
old_mmap(NULL, 17, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0xb75f7000
close(3) = 0
open("/etc/libcwait.so", O_RDONLY) = 3
read(3, "177ELF111 3 3 1 3404 "..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=4431, ...}) = 0
old_mmap(NULL, 5912, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x61e000
old_mmap(0x61f000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0) =
0x61f000
close(3) = 0
munmap(0xb75f7000, 17) = 0
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=86552, ...}) = 0
old_mmap(NULL, 86552, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb75e2000
close(3) = 0
open("/lib/tls/libc.so.6", O_RDONLY) = 3
read(3, "177ELF111 3 3 1 200X1"..., 512) = 512
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb75e1000
fstat64(3, {st_mode=S_IFREG|0755, st_size=1568924, ...}) = 0
old_mmap(NULL, 1276876, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x111000
old_mmap(0x243000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x131000) =
0x243000
old_mmap(0x247000, 7116, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,
-1, 0) = 0x247000
close(3) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e17c0, limit:1048575,
seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0,
useable:1}) = 0
munmap(0xb75e2000, 86552) = 0
open("/boot/vmlinuz-2.4.21-20.EL", O_RDONLY) = 3
open("output", O_WRONLY|O_CREAT, 0600) = 4
sendfile(4, 3, [0], 10000000) = 1243768
fstat64(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfffb950) = -1 ENOTTY (Inappropriate ioctl
for device)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xb75f7000
write(1, "size = 1243768, off = 1243768
", 30) = 30
munmap(0xb75f7000, 4096) = 0
exit_group(30) = ?
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
前面没仔细看,manpage里有这一句
In Linux 2.4 and earlier, out_fd could refer to a regular file, and send-
file() changed the current offset of that file.
还不清楚为什么2.6不能再引用常规文件
|
|
----
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
|
你的方法是有问题的,要是文件名中有空格怎么办?如果有分号呢?要是更狠一点我把file_s定义为'a b;' file_o 定义为'rm /etc/passwd' 呢
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
|
你说的那种情况,要有root权限才可以执行的,所以在linux,root 的权限是不能随便让人获得的.那是非常危险的.有空格的那种情部你要自已考虑i,不过(如果我没记错的话)文件名里是不欢许有;号的吧,
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
谁说文件名中不允许分号的?
firewall:/tmp# touch 'adb;dedf;a'
firewall:/tmp# ls -l
total 0
-rw-r--r-- 1 root root 0 May 29 08:29 adb;dedf;a
|
|
[Original]
[Print]
[Top]
|
|