arbow发现的问题如下:
4> file:read_file("/proc/cpuinfo").
{ok,<<>>}
11> {ok, IoDevice} = file:open("/proc/cpuinfo", [binary]),file:read(IoDevice, 1024).
{ok,<<"processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 15\nmodel name\t: Intel(R) Core(TM)2 CPU "...>>}
同样的虚拟文件 不同的读法一个有内容 一个没有。
真实的文件就不存在这个问题。
erl -smp disable (禁止多smp的原因是容易找到pid)
strace -p PID
结果如下:
。。。。
[color=blue]stat("/proc/cpuinfo", {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
open("/proc/cpuinfo", O_RDONLY) = 7
close(7) = 0[/color]
[color=orange]stat("/proc/cpuinfo", {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
open("/proc/cpuinfo", O_RDONLY) = 7
poll([{fd=3, events=POLLIN|POLLRDNORM}, {fd=5, events=POLLIN|POLLRDNORM}, {fd=0, events=POLLIN|POLLRDNORM}], 3, 0) = 0
clock_gettime(CLOCK_MONOTONIC, {457571, 853399847}) = 0
read(7, "processor\t: 0\nvendor_id\t: Genuin"..., 8192) = 1238[/color]
看下源码红色部分:
static void invoke_read_file(void *data)
{
struct t_data *d = (struct t_data *) data;
size_t read_size;
int chop;
if (! d->c.read_file.binp) {
int fd;
int size;
if (! (d->result_ok =
efile_openfile(&d->errInfo, d->c.read_file.name,
EFILE_MODE_READ, &fd, &d->c.read_file.size))) {
goto done;
}
d->fd = fd;
size = (int) d->c.read_file.size;
if (size != d->c.read_file.size ||
! (d->c.read_file.binp = driver_alloc_binary(size))) {
d->result_ok = 0;
d->errInfo.posix_errno = ENOMEM;
goto close;
}
d->c.read_file.offset = 0;
}
read_size = (size_t) (d->c.read_file.size - d->c.read_file.offset);
[color=red] if (! read_size) goto close;[/color]
chop = d->again && read_size >= FILE_SEGMENT_READ*2;
if (chop) read_size = FILE_SEGMENT_READ;
d->result_ok =
efile_read(&d->errInfo,
EFILE_MODE_READ,
(int) d->fd,
d->c.read_file.binp->orig_bytes + d->c.read_file.offset,
read_size,
&read_size);
if (d->result_ok) {
d->c.read_file.offset += read_size;
if (chop) return; /* again */
}
[color=red] close:
efile_closefile((int) d->fd);[/color]
done:
d->again = 0;
}
static void invoke_read(void *data)
{
struct t_data *d = (struct t_data *) data;
int status, segment;
size_t size, read_size;
segment = d->again && d->c.read.bin_size >= 2*FILE_SEGMENT_READ;
if (segment) {
size = FILE_SEGMENT_READ;
} else {
size = d->c.read.bin_size;
}
read_size = size;
if (d->flags & EFILE_COMPRESSED) {
read_size = erts_gzread((gzFile)d->fd,
d->c.read.binp->orig_bytes + d->c.read.bin_offset,
size);
status = (read_size != -1);
if (!status) {
d->errInfo.posix_errno = EIO;
}
} else {
status = efile_read(&d->errInfo, d->flags, (int) d->fd,
d->c.read.binp->orig_bytes + d->c.read.bin_offset,
size,
&read_size);
}
if ( (d->result_ok = status)) {
ASSERT(read_size <= size);
d->c.read.bin_offset += read_size;
if (read_size < size || !segment) {
d->c.read.bin_size = 0;
d->again = 0;
} else {
d->c.read.bin_size -= read_size;
}
} else {
d->again = 0;
}
}
也就是说read_file 在发现文件长度为0的时候 [color=red]不进行进一步读取[/color].所以使用的时候请注意。
4> file:read_file("/proc/cpuinfo").
{ok,<<>>}
11> {ok, IoDevice} = file:open("/proc/cpuinfo", [binary]),file:read(IoDevice, 1024).
{ok,<<"processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 15\nmodel name\t: Intel(R) Core(TM)2 CPU "...>>}
同样的虚拟文件 不同的读法一个有内容 一个没有。
真实的文件就不存在这个问题。
erl -smp disable (禁止多smp的原因是容易找到pid)
strace -p PID
结果如下:
。。。。
[color=blue]stat("/proc/cpuinfo", {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
open("/proc/cpuinfo", O_RDONLY) = 7
close(7) = 0[/color]
[color=orange]stat("/proc/cpuinfo", {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
open("/proc/cpuinfo", O_RDONLY) = 7
poll([{fd=3, events=POLLIN|POLLRDNORM}, {fd=5, events=POLLIN|POLLRDNORM}, {fd=0, events=POLLIN|POLLRDNORM}], 3, 0) = 0
clock_gettime(CLOCK_MONOTONIC, {457571, 853399847}) = 0
read(7, "processor\t: 0\nvendor_id\t: Genuin"..., 8192) = 1238[/color]
看下源码红色部分:
static void invoke_read_file(void *data)
{
struct t_data *d = (struct t_data *) data;
size_t read_size;
int chop;
if (! d->c.read_file.binp) {
int fd;
int size;
if (! (d->result_ok =
efile_openfile(&d->errInfo, d->c.read_file.name,
EFILE_MODE_READ, &fd, &d->c.read_file.size))) {
goto done;
}
d->fd = fd;
size = (int) d->c.read_file.size;
if (size != d->c.read_file.size ||
! (d->c.read_file.binp = driver_alloc_binary(size))) {
d->result_ok = 0;
d->errInfo.posix_errno = ENOMEM;
goto close;
}
d->c.read_file.offset = 0;
}
read_size = (size_t) (d->c.read_file.size - d->c.read_file.offset);
[color=red] if (! read_size) goto close;[/color]
chop = d->again && read_size >= FILE_SEGMENT_READ*2;
if (chop) read_size = FILE_SEGMENT_READ;
d->result_ok =
efile_read(&d->errInfo,
EFILE_MODE_READ,
(int) d->fd,
d->c.read_file.binp->orig_bytes + d->c.read_file.offset,
read_size,
&read_size);
if (d->result_ok) {
d->c.read_file.offset += read_size;
if (chop) return; /* again */
}
[color=red] close:
efile_closefile((int) d->fd);[/color]
done:
d->again = 0;
}
static void invoke_read(void *data)
{
struct t_data *d = (struct t_data *) data;
int status, segment;
size_t size, read_size;
segment = d->again && d->c.read.bin_size >= 2*FILE_SEGMENT_READ;
if (segment) {
size = FILE_SEGMENT_READ;
} else {
size = d->c.read.bin_size;
}
read_size = size;
if (d->flags & EFILE_COMPRESSED) {
read_size = erts_gzread((gzFile)d->fd,
d->c.read.binp->orig_bytes + d->c.read.bin_offset,
size);
status = (read_size != -1);
if (!status) {
d->errInfo.posix_errno = EIO;
}
} else {
status = efile_read(&d->errInfo, d->flags, (int) d->fd,
d->c.read.binp->orig_bytes + d->c.read.bin_offset,
size,
&read_size);
}
if ( (d->result_ok = status)) {
ASSERT(read_size <= size);
d->c.read.bin_offset += read_size;
if (read_size < size || !segment) {
d->c.read.bin_size = 0;
d->again = 0;
} else {
d->c.read.bin_size -= read_size;
}
} else {
d->again = 0;
}
}
也就是说read_file 在发现文件长度为0的时候 [color=red]不进行进一步读取[/color].所以使用的时候请注意。