我想实现一个合适的 write(2)循环接受一个缓冲区并不断调用 write 直到整个缓冲区被写入。
我想基本的方法是这样的:
/** write len bytes of buf to fd, returns 0 on success */
int write_fully(int fd, char *buf, size_t len) {
while (len > 0) {
ssize_t written = write(fd, buf, len);
if (written < 0) {
// some kind of error, probably should try again if its EINTR?
return written;
}
buf += written;
len -= written;
}
return 0;
}
...但这提出了一个问题,即 write() 是否可以有效地返回写入的 0 字节以及在这种情况下该怎么做。如果这种情况持续存在,上面的代码只会在 write 调用上热旋转,这似乎是个坏主意。只要返回不是零的,您就在取得进展。
write 的手册页有点模棱两可。它说,例如:
On success, the number of bytes written is returned (zero indicates nothing was written).
这似乎表明在某些场景下是可能的。只有一种这样的场景被明确指出:
If count is zero and fd refers to a regular file, then write() may return a failure status if one of the errors below is detected. If no errors are detected, or error detection is not performed, 0 will be returned without causing any other effect. If count is zero and fd refers to a file other than a regular file, the results are not specified.
上面避免了这种情况,因为我从不使用 len == 0 调用 write。还有很多其他情况无法写入任何内容,但通常它们都有与之关联的特定错误代码。
文件本身将根据命令行中给出的路径/名称打开。所以它通常是一个常规文件,但用户当然可以传递诸如管道之类的东西,进行输入重定向,传递诸如 /dev/stdout 之类的特殊设备等等。我至少可以控制 open 调用,并且 O_NONBLOCK 标志不会传递给 open。我无法合理地检查所有文件系统、所有特殊设备的行为(即使我可以,也会添加更多),所以我想知道如何以合理和通用的方式处理这个问题.
* ... 对于非零缓冲区大小。
最佳答案
除非您不顾一切地调用未指定的行为,否则您不会从 write() 返回零结果,除非您尝试写入零字节(问题中的代码避免这样做)。
我相信 write() 的 POSIX 规范涵盖了这个问题。
The write() function shall attempt to write nbyte bytes from the buffer pointed to by buf to the file associated with the open file descriptor, fildes.
Before any action described below is taken, and if nbyte is zero and the file is a regular file, the write() function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, the write() function shall return zero and have no other results. If nbyte is zero and the file is not a regular file, the results are unspecified.
这说明如果您请求写入零字节,您可能会得到零返回值,但有一些警告 — 它必须是一个常规文件,如果像 EBADF 这样的错误是您可能会得到一个错误检测到,并且未指定如果文件描述符不引用常规文件会发生什么。
If a write() requests that more bytes be written than there is room for (for example, [XSI]⌦ the file size limit of the process or ⌫ the physical end of a medium), only as many bytes as there is room for shall be written. For example, suppose there is space for 20 bytes more in a file before reaching a limit. A write of 512 bytes will return 20. The next write of a non-zero number of bytes would give a failure return (except as noted below).
[XSI]⌦ If the request would cause the file size to exceed the soft file size limit for the process and there is no room for any bytes to be written, the request shall fail and the implementation shall generate the SIGXFSZ signal for the thread. ⌫
If write() is interrupted by a signal before it writes any data, it shall return -1 with errno set to [EINTR].
If write() is interrupted by a signal after it successfully writes some data, it shall return the number of bytes written.
If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.
这些规则并没有真正允许返回 0(尽管学究可能会说太大的 nbyte 值可能被定义为返回 0)。
When attempting to write to a file descriptor (other than a pipe or FIFO) that supports non-blocking writes and cannot accept the data immediately:
If the O_NONBLOCK flag is clear, write() shall block the calling thread until the data can be accepted.
If the O_NONBLOCK flag is set, write() shall not block the thread. If some data can be written without blocking the thread, write() shall write what it can and return the number of bytes written. Otherwise, it shall return -1 and set errno to [EAGAIN].
…details for obscure file types — a number of them with unspecified behaviour…
Return value
Upon successful completion, these functions shall return the number of bytes actually written to the file associated with fildes. This number shall never be greater than byte. Otherwise, -1 shall be returned and errno set to indicate the error.
因此,由于您的代码避免尝试写入零字节,只要 len 不大于 {SSIZE_MAX},并且只要您不写入模糊的文件类型(如共享内存对象或类型化内存)对象)你不应该看到 write() 返回零。
稍后在 write() 的 POSIX 页面的基本原理部分中,有以下信息:
Where this volume of POSIX.1-2008 requires
-1to be returned anderrnoset to [EAGAIN], most historical implementations return zero (with theO_NDELAYflag set, which is the historical predecessor ofO_NONBLOCK, but is not itself in this volume of POSIX.1-2008). The error indications in this volume of POSIX.1-2008 were chosen so that an application can distinguish these cases from end-of-file. Whilewrite()cannot receive an indication of end-of-file,read()can, and the two functions have similar return values. Also, some existing systems (for example, Eighth Edition) permit a write of zero bytes to mean that the reader should get an end-of-file indication; for those systems, a return value of zero fromwrite()indicates a successful write of an end-of-file indication.
因此,尽管 POSIX(即使不是全部,也很大程度上)排除了从 write() 返回零的可能性,但相关系统上的现有技术确实使 write() 返回零。
关于write(2) 能否返回写入的 0 个字节*,如果返回怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904221/
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
所以我开始关注ruby,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出
给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R
我在我的Rails3示例应用程序上使用CarrierWave。我想验证远程位置上传,因此当用户提交无效URL(空白或非图像)时,我不会收到标准错误异常:CarrierWave::DownloadErrorinImageController#createtryingtodownloadafilewhichisnotservedoverHTTP这是我的模型:classPaintingtrue,:length=>{:minimum=>5,:maximum=>100}validates:image,:presence=>trueend这是我的Controller:classPaintingsC