Java InputStream の内容を OutputStream に書き込む簡単な方法
質問
今日、文書の内容を書くための簡単な方法を追跡できないことに気づき、驚きました。 InputStream
に OutputStream
ジャワでは。明らかに、バイト バッファー コードを書くのは難しくありませんが、作業を容易にする (そしてコードをより明確にする) 何かが欠けているだけではないかと思います。
したがって、与えられた InputStream
in
と OutputStream
out
, 、以下をもっと簡単に書く方法はありますか?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
解決
Java 7 を使用している場合は、 ファイル (標準ライブラリ内) が最良のアプローチです。
/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)
編集:もちろん、これはファイルから InputStream または OutputStream のいずれかを作成する場合にのみ役立ちます。使用 file.toPath()
ファイルからパスを取得します。
既存のファイルに書き込むには (例:で作成されたもの File.createTempFile()
)、次のパラメータを渡す必要があります。 REPLACE_EXISTING
コピー オプション (それ以外の場合) FileAlreadyExistsException
がスローされます):
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)
他のヒント
WMR が述べたように、 org.apache.commons.io.IOUtils
Apache には というメソッドがあります copy(InputStream,OutputStream)
これはまさにあなたが探していることを行います。
したがって、次のようになります。
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
...コード内で。
避けている理由はありますか IOUtils
?
Java9
Java9以降、 InputStream
というメソッドを提供します transferTo
次の署名付き:
public long transferTo(OutputStream out) throws IOException
として ドキュメンテーション 州、 transferTo
意思:
この入力ストリームからすべてのバイトを読み取り、読み取られる順に、特定の出力ストリームにバイトを書き込みます。返品後、この入力ストリームはストリームの終わりになります。この方法はどちらのストリームも閉じません。
この方法では、入力ストリームから無期限に読み取るか、出力ストリームに書き込みます。入力および/または出力ストリームが非同期に閉じられている場合、または転送中に中断されたスレッドが高度に入力および出力ストリームが特異的であるため、指定されていない場合の動作
Javaのコンテンツを記述するには InputStream
に OutputStream
, 、 あなたは書ける:
input.transferTo(output);
これでうまくいくと思いますが、必ずテストしてください...マイナーな「改善」ですが、読みやすさに少しコストがかかるかもしれません。
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
グアバを使って ByteStreams.copy()
:
ByteStreams.copy(inputStream, outputStream);
シンプルな機能
を書くためだけにこれが必要な場合は、 InputStream
に File
次に、この単純な関数を使用できます。
private void copyInputStreamToFile( InputStream in, File file ) {
try {
OutputStream out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
PipedInputStream
そして PipedOutputStream
複数のスレッドがある場合にのみ使用してください。 Javadoc に記載されている.
また、入力ストリームと出力ストリームはスレッド割り込みをラップしないことに注意してください。 IOException
そ...したがって、コードに中断ポリシーを組み込むことを検討する必要があります。
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
これは、大量のデータ、または耐えられないほど長時間停止しているストリームからのデータをコピーするためにこの API を使用する予定がある場合に便利な追加機能です。
の JDK
は同じコードを使用しているため、不格好なサードパーティのライブラリ(おそらく何も違うことはしないでしょう)なしで「簡単な」方法はないようです。以下は直接コピーしたものです java.nio.file.Files.java
:
// buffer size used for reading and writing
private static final int BUFFER_SIZE = 8192;
/**
* Reads all bytes from an input stream and writes them to an output stream.
*/
private static long copy(InputStream source, OutputStream sink)
throws IOException
{
long nread = 0L;
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = source.read(buf)) > 0) {
sink.write(buf, 0, n);
nread += n;
}
return nread;
}
ご利用される方へ スプリングフレームワーク 便利なものがあります ストリームユーティリティ クラス:
StreamUtils.copy(in, out);
上記ではストリームは閉じられません。コピー後にストリームを閉じたい場合は、次を使用します。 ファイルコピーユーティリティ 代わりにクラス:
FileCopyUtils.copy(in, out);
JDK メソッドを使用してこれをもっと簡単に行う方法はありませんが、Apocalisp がすでに述べたように、このアイデアを持っているのはあなただけではありません。使用できます IOUtils から ジャカルタ コモンズ IO, 、他にも便利なものがたくさんありますが、IMO は実際には JDK の一部である必要があります...
Java7を使用し、 リソースを試す, 、簡略化された読みやすいバージョンが付属しています。
try(InputStream inputStream = new FileInputStream("C:\\mov.mp4");
OutputStream outputStream = new FileOutputStream("D:\\mov.mp4")){
byte[] buffer = new byte[10*1024];
for (int length; (length = inputStream.read(buffer)) != -1; ){
outputStream.write(buffer, 0, length);
}
}catch (FileNotFoundException exception){
exception.printStackTrace();
}catch (IOException ioException){
ioException.printStackTrace();
}
Commons Net の Util クラスを使用します。
import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);
ここでは、最も単純な for ループをどのように実行しているかを示します。
private void copy(final InputStream in, final OutputStream out)
throws IOException {
final byte[] b = new byte[8192];
for (int r; (r = in.read(b)) != -1;) {
out.write(b, 0, r);
}
}
私見のより最小限のスニペット(長さ変数の範囲もより狭くなります):
byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
out.write(buffer, 0, n);
余談ですが、なぜ多くの人が を使用しないのか理解できません。 for
ループの代わりに、 while
一部の人には「貧弱な」スタイルとみなされている割り当てとテストの式を使用しています。
ほとんどのファイルは 1024 バイトを超えるため、大きなバッファを使用する方が良いと思います。また、読み取りバイト数が正であることを確認することをお勧めします。
byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
out.write(buffer, 0, n);
}
out.close();
PipedInputStream と PipedOutputStream は、一方を他方に接続できるため、何らかの用途に使用できる可能性があります。
もう 1 つの候補としては、Guava I/O ユーティリティがあります。
http://code.google.com/p/guava-libraries/wiki/IOExplained
Guava は私のプロジェクトですでに非常に便利なので、1 つの関数にさらに別のライブラリを追加するのではなく、これらを使用しようと考えました。
私が使う BufferedInputStream
そして BufferedOutputStream
コードからバッファリングセマンティクスを削除するには
try (OutputStream out = new BufferedOutputStream(...);
InputStream in = new BufferedInputStream(...))) {
int ch;
while ((ch = in.read()) != -1) {
out.write(ch);
}
}
public static boolean copyFile(InputStream inputStream, OutputStream out) {
byte buf[] = new byte[1024];
int len;
long startTime=System.currentTimeMillis();
try {
while ((len = inputStream.read(buf)) != -1) {
out.write(buf, 0, len);
}
long endTime=System.currentTimeMillis()-startTime;
Log.v("","Time taken to transfer all bytes is : "+endTime);
out.close();
inputStream.close();
} catch (IOException e) {
return false;
}
return true;
}
試す サボテン:
new LengthOf(new TeeInput(input, output)).value();
詳細はこちら: http://www.yegor256.com/2017/06/22/object-志向-input-output-in-cactoos.html
この方法を使用できます
public static void copyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}