如何转换从管道接收到的二进制数
Posted
技术标签:
【中文标题】如何转换从管道接收到的二进制数【英文标题】:How to convert binary numbers received from a pipe 【发布时间】:2021-09-18 20:12:18 【问题描述】:我有一个包含一系列数字的管道。 我会阅读它,并且在每次迭代中,我都会将读取的内容写入一个 txt 文件。 如何将二进制数转换为十进制数并将它们记录在我的 txt 文件中,每行一个?
PS 管道在另一个文件中创建并使用以下命令写入数字:
write (fp, &mynum, sizeof (mynum));
主文件
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
int fd, fp ;
int bytesread;
char * myfifo = "myfifo";
char buf[MAX_BUF];
int count = 0;
char *filename = "memorizza.txt";
fp = open(filename,O_WRONLY | O_APPEND);
if ((fd = open(myfifo, O_RDONLY))==-1 ) // opening pipe
perror(myfifo);
return 1;
while(1)
if((bytesread = read( fd, buf, MAX_BUF - 1)) > 0) //read pipe
buf[bytesread] = '\0';
count++;
write(fp , buf , MAX_BUF );
else
printf("Ho ricevuto %d numeri primi \n" , count);
break;
close(fd);
close(fp);
return 0;
【问题讨论】:
如果您有字符,Write 可用于文本文件。它会给二进制数据带来不可读的结果。 好的,所以首先我应该将从管道中读取的内容从二进制转换为字符,然后将其写入文件? 数字是如何写入管道的?作为文本还是二进制值?对于二进制你需要转换 (fprintf
),对于文本你需要考虑分隔符。
@LucaLucazzo 请edit您的问题并在此处添加所有要求的信息或说明。添加一个简单的示例程序,将一些硬编码的数字写入管道。从管道读取时,您不能假设获得的字节数与使用单个 write
调用写入的字节数相同。您可能会得到任意数量的字节,一个以上的数字或部分数字,因此您必须检查 read
的返回值以找出它已读取到缓冲区的字节数。而不是写入/读取二进制数据,fprintf
文本格式的数字可能会更好,例如每行一个。
您确定您使用的是管道吗?看起来您正在使用文件。看看documentation about pipes。
【参考方案1】:
要从文件描述符中读取二进制编码的 int(假设主机字节顺序),您必须将指向 int
的指针传递给 read
,并准确读取 sizeof(int)
字节。一个简单的实现应该是这样的:
int i;
ssize_t e = read(fd, &i, sizeof(i));
这个实现的问题是 read 不能保证一次性给你所有你要求的字节。所以我们必须继续阅读,直到我们有所有的字节:
int i;
char *buffer = (char *)&i;
size_t left_to_read = sizeof(i);
while (left_to_read)
ssize_t e = read(fd, buffer, left_to_read);
if (e < 0 && errno != EINTR)
perror("Failure reading from file descriptor");
exit(EXIT_FAILURE);
else if (e == 0)
/*
Handle EOF
*/
else if (e > 0)
left_to_read -= e;
buffer += e;
编辑:
读完int
后自然可以正常方式转换为ascii:
fprintf(outfile, "%d\n", i);
【讨论】:
我只想补充一点,我的解决方案比它需要的要慢。该实现为每个int
调用至少1 个read
。在典型的操作系统上,每个read
都会在内核中进行一次上下文切换,这很慢。最好读入比sizeof(int)
更大的缓冲区,然后从该缓冲区中提取单个整数。如果额外的复杂性是值得的,那么获得的加速是你必须决定的。【参考方案2】:
第一个近似值,如果你用
写入管道write (fp, & mynum, sizeof (mynum));
(引自 cmets),其中mynum
的类型为int
,则相应的读取将是
int fp = /* open read end of the pipe */;
int my_read_num;
read(fp, &my_read_num, sizeof(my_read_num));
当它按预期工作时,它会为您提供所需的整数作为int
,然后您可以通过fprintf()
发出它而无需进一步操作,或者用它做任何您通常可能用@987654327 做的事情@。
但也有并发症,包括:
write()
和 read()
都不能保证传输请求的全部字节数。它们的返回值告诉您它们实际传输了多少字节,并且健壮的代码需要考虑短写入和读取,通常通过额外的write
或read
调用来传输任何剩余的字节,视情况而定。
对write()
和read()
的调用不能保证自动配对。也就是说,多个write()
s 写入的数据可能会被单个read()
读取,反之亦然。但是,对于您的特定情况,这不是什么大问题(一旦处理(1)),因为您正在传输已知大小的单位。它通常会咬那些试图传输不同长度数据(例如文本行)的人,而没有建立一种方法来传达消息长度或边界。
总的来说,您不一定要依赖两个端点来使用相同的整数表示。例如,一端可能对int
使用32 位大端,而另一端对int
使用16 位小端。有一些方法可以解决这个问题,但在您的特定情况下,您无需担心它,即两端都在同一台机器上运行,并为它们传输的对象使用相同的 C 数据类型。
【讨论】:
以上是关于如何转换从管道接收到的二进制数的主要内容,如果未能解决你的问题,请参考以下文章