我有一个模块负责读取,处理和写入磁盘的字节.字节通过UDP传入,在汇编各个数据报之后,处理并写入磁盘的最终字节数组通常在200字节到500,000字节之间.偶尔会有一些字节数组,在汇编后,超过500,000字节,但这些数组相对较少.
我现在正在使用FileOutputStream的write(byte\[\])方法.我也在尝试包装FileOutputStreamin BufferedOutputStream,包括使用接受缓冲区大小作为参数的构造函数.
似乎使用的BufferedOutputStream是趋向于略微更好的性能,但我只是开始尝试不同的缓冲区大小.我只有一组有限的样本数据可供使用(来自样本运行的两个数据集,我可以通过我的应用程序管道).是否有一般的经验法则我可以应用于尝试计算最佳缓冲区大小以减少磁盘写入并最大化磁盘写入的性能,因为我知道有关我正在编写的数据的信息?
为了在Java中获得最快的TCP传输速度,这是更好的:
选项A:
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
Run Code Online (Sandbox Code Playgroud)
选项B:
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
Run Code Online (Sandbox Code Playgroud)
我已经读过,当将8 KiB写入OutputStream时,性能会受到影响,建议它一次性写入小块而不是pver 8 KiB.8 KiB是BufferedOutputStream的默认缓冲区大小.
但是我还读到,当通过网络传输数据时,尽可能快地清除字节是很好的.这意味着使用缓冲区并以小块写入会增加不必要的开销.
那么,选项A还是选项B?哪个效果最好?
现在我猜测选项A提供了最高的传输速度,同时消耗了比选项B更多的CPU.选项B可能更好,因为它没有那么慢,但节省了大量的CPU.
-
奖金问题:触摸TCP窗口大小是个好主意吗?例如,将其设置为64 KiB:
socket.setReceiveBufferSize(65536);
socket.setSendBufferSize(65536);
Run Code Online (Sandbox Code Playgroud)
我尝试在测试机器上将其设置为128 KiB,因为我读到它可以提高速度但是当服务器有几个连接时,CPU是100%而不是2%,就像我单独离开时一样.我猜128 KiB太高了,除非你有一台能够处理流量急流的好服务器,但将它设置为32 KiB是否明智?我认为我的默认值是8 KiB.
("socket"是"java.net.Socket")
我一直在寻找答案,但实际上找不到任何东西.今天早些时候,我问我如何通过字节数组将文件转换为字符串,然后再返回,以便稍后检索.
人们告诉我的是,我必须只存储字节数组,以避免令人讨厌的编码问题.所以现在我已经开始研究了这个问题,但现在我已经碰壁了.
基本上,我之前使用过无缓冲的流,将文件转换为字节数组.这在理论上很好用,但它会占用大量内存,最终会导致堆大小异常.我应该使用缓冲流(或者我被告知),而我现在遇到的问题是从BufferedInputStream到byte [].我试图复制并使用本文档中的方法
我为缓冲流交换无缓冲流的地方.唯一的问题是,我不能直接将缓冲输出流转换为字节数组,因为我可以使用无缓冲的流.
救命?:)
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public final class BufferedByteStream {
private static final int BUF_SIZE = 1024000;
public static long copy(BufferedInputStream from, BufferedOutputStream to) throws IOException {
byte[] buf = new byte[BUF_SIZE];
long total = 0;
while(true) {
int r = from.read(buf);
if(r == -1) {
break;
}
to.write(buf, 0, r);
total += r;
}
return total;
}
public static byte[] toByteArray(BufferedInputStream in) throws IOException {
BufferedOutputStream out = new …Run Code Online (Sandbox Code Playgroud) 我想连续打印没有换行的点(等待行为).
这个bash one-liner在我的机器上工作正常:
$ while true; do sleep 1; printf '.'; done
.......^C
Run Code Online (Sandbox Code Playgroud)
但是,当我在Docker容器中运行它时,当我尝试使用docker日志读取其输出时,不会打印输出:
$ docker run -d --name test_logs ubuntu:14.04 bash -c "while true; do sleep 1; printf '.'; done"
60627015ed0a0d331a26e0c48ccad31c641f2142da55d24e10f7ad5737211a18
$ docker logs test_logs
$ docker logs -f test_logs
^C
Run Code Online (Sandbox Code Playgroud)
我可以通过使用strace进程1(bash命令)确认bash循环正在容器中执行:
$ docker exec -t test bash -c 'apt-get install -y strace; strace -p1 -s9999 -e write'
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
strace …Run Code Online (Sandbox Code Playgroud) 我正在尝试发布图像的上传进度,使用okhttp作为我的客户端和mimecraft来上传它们以打包多部分文件。
当数据被写入套接字时,我添加了日志以写入字节数(如果我能正确告诉的话,以4kb的块为单位),然后上传。
问题是,虽然每次写入数据块时我都会在输出流上调用flush,但直到将〜800kb写入输出流后,似乎都没有上载。一旦达到该点,它似乎会上传〜100kb,然后该应用再向输出流写入另外100kb(如释放的空间,可以写更多一点),然后继续。
这样的结果是(通过1.2mb文件)前800kb几乎立即被写入/报告,然后开始上载(通过charles网络软件跟踪),然后在下一个800kb中开始读取/写入/上载100kb几秒钟后,一旦我将最后一个字节写入输出流,应用程序就会报告已写入100%的上传内容。尽管这是正确的,但由于网络客户端仍在上传仍在网络缓冲区中的最后800kb,它又在那儿坐了5-10秒,然后才完成请求。
有没有人有这种经验,或者知道这是否是okhttp中的常见问题?
干杯
编辑:如果我上传的文件少于800kb,我测试了250kb和500kb,它们在上传之前立即被100%写入流中,但是3mb的图像仍将上传800kb,然后以大约100kb的块数滴答,并且每次写入一些文件时,写入循环都会坐在那里,另外写入100kb。
我理解背后的理论BufferedOutputStream.字节被写入缓冲区数组直到它已满,然后写入(刷新)到底层流 - 这个想法是它比逐字节写入更快,因为OS调用更少.
但是,通过查看BufferedOutputStream类和方法(BufferedOutputStream.java)的实现,似乎最终,缓冲区中的字节只是逐字节写入.
我认为情况是这样的,因为:
在BufferedOutputStream.write(byte b [],int off,int len)中,它有行out.write(b,off,len).由于out是OutputStream的实例,而不是BufferedOutputStream,因此它调用OutputStream.write(byte [],int,int).这又使用for循环逐字节写入
请有人澄清实际发生了什么,以及它如何更快?
我正在尝试使用BufferedInputStream &读取和写入大文件(大于100 MB)BufferedOutputStream.我收到了内存问题和OOM异常.
代码如下:
BufferedInputStream buffIn = new BufferedInputStream(iStream);
/** iStream is the InputStream object **/
BufferedOutputStream buffOut=new BufferedOutputStream(new FileOutputStream(file));
byte []arr = new byte [1024 * 1024];
int available = -1;
while((available = buffIn.read(arr)) > 0) {
buffOut.write(arr, 0, available);
}
buffOut.flush();
buffOut.close();
Run Code Online (Sandbox Code Playgroud)
我的问题是当我们使用BufferedOutputStreeam它是否持有内存直到写出完整的文件?
使用大写文件的最佳方法是什么BufferedOutputStream?
我想用bufferedInputStream和bufferedOutputStream大型的二进制文件从源文件复制到目标文件.
这是我的代码:
byte[] buffer = new byte[1000];
try {
FileInputStream fis = new FileInputStream(args[0]);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(args[1]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int numBytes;
while ((numBytes = bis.read(buffer))!= -1)
{
bos.write(buffer);
}
//bos.flush();
//bos.write("\u001a");
System.out.println(args[0]+ " is successfully copied to "+args[1]);
bis.close();
bos.close();
} catch (IOException e)
{
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
我可以成功复制,但后来我使用
cmp src dest
Run Code Online (Sandbox Code Playgroud)
在命令行中比较两个文件.错误消息
cmp:文件上的EOF
出现.我可以知道我哪里错了吗?
根据API,这些是事实:
seek(long bytePosition)简单的说法,将指针移动到与指定的位置bytePosition的参数。bytePosition大于文件长度时,除非在(新)末尾写入一个字节,否则文件长度不会改变。但是,我好奇的情况是:当有一个没有数据的文件(0字节)时,我执行以下代码:
file.seek(100000-1);
file.write(0);
Run Code Online (Sandbox Code Playgroud)
所有的100,000个字节0几乎立即被填满。我可以说10毫秒超过200GB。
但是,当我尝试使用其他方法(例如BufferedOutputStream同一进程)写入100000字节时,将花费几乎无限长的时间。
时间差异的原因是什么?有没有更有效的方法来创建n字节文件并用0s 填充?
编辑: 如果没有实际写入数据,文件中如何填充数据?示例代码:
RandomAccessFile out=new RandomAccessFile("D:/out","rw");
out.seek(100000-1);
out.write(0);
out.close();
Run Code Online (Sandbox Code Playgroud)
这是输出:
另外,如果文件足够大,由于空间不足,我将无法再写入磁盘。
我正在阅读Paul Graham 出版的ANSI Common Lisp一书,这是一个例子:
(defun ask-number ()
(format t "Please enter a number. ")
(let ((val (read)))
(if (numberp val)
val
(ask-number))))
Run Code Online (Sandbox Code Playgroud)
它应该像这样:
$(问号)
请输入一个号码.一个
请输入一个号码.(哼哼)
请输入一个号码.52
52
但是当我尝试它(SBCL 1.0.55)时,它在成功读取之前不会打印格式字符串:
$(问号)
一个
(哼哼)
52
请输入一个号码.请输入一个号码.请输入一个号码.
52
哪里出错?如何使其表现出预期的方式?