Saya terkejut menemukan hari ini bahwa saya tidak dapat melacak cara sederhana untuk menulis konten InputStream
ke OutputStream
di Jawa. Jelas, kode buffer byte tidak sulit untuk ditulis, tetapi saya curiga saya hanya melewatkan sesuatu yang akan membuat hidup saya lebih mudah (dan kode lebih jelas).
Jadi, mengingat InputStream
in
dan OutputStream
out
, apakah ada cara yang lebih sederhana untuk menulis yang berikut ini?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Jawaban:
Jawa 9
Sejak Java 9,
InputStream
berikan metode yang disebuttransferTo
dengan tanda tangan berikut:Seperti yang dinyatakan dalam dokumentasi ,
transferTo
akan:Jadi untuk menulis konten Java
InputStream
keOutputStream
, Anda dapat menulis:sumber
Files.copy
sebanyak mungkin. Ini diimplementasikan dalam kode asli dan karenanya bisa lebih cepat.transferTo
harus digunakan hanya jika kedua aliran bukan FileInputStream / FileOutputStream.Files.copy
tidak menangani setiap input / output stream tapi itu khusus dirancang untuk berkas sungai.Seperti disebutkan WMR,
org.apache.commons.io.IOUtils
dari Apache memiliki metode yang disebutcopy(InputStream,OutputStream)
yang tidak persis apa yang Anda cari.Jadi kamu punya:
... dalam kode Anda.
Apakah ada alasan Anda menghindarinya
IOUtils
?sumber
in
danout
harus ditutup pada akhir kode di blok akhirnyaJika Anda menggunakan Java 7, File (di perpustakaan standar) adalah pendekatan terbaik:
Sunting: Tentu saja itu hanya berguna ketika Anda membuat salah satu dari InputStream atau OutputStream dari file. Gunakan
file.toPath()
untuk mendapatkan jalur dari file.Untuk menulis ke file yang sudah ada (misalnya yang dibuat dengan
File.createTempFile()
), Anda harus melewatiREPLACE_EXISTING
opsi salin (jikaFileAlreadyExistsException
tidak dilempar):sumber
Files
TIDAK tersedia di Android 1.7 Java. Saya tersengat oleh ini: stackoverflow.com/questions/24869323/…Files.copy()
yang mengambil dua aliran, dan adalah apa yang semuaFiles.copy()
fungsi lain maju untuk melakukan pekerjaan yang sebenarnya menyalin. Namun, itu pribadi (karena sebenarnya tidak melibatkan Paths atau File pada tahap itu), dan terlihat persis seperti kode dalam pertanyaan OP sendiri (ditambah pernyataan pengembalian). Tidak ada pembukaan, tidak ada penutupan, hanya salinan lingkaran.Saya pikir ini akan berhasil, tetapi pastikan untuk mengujinya ... "perbaikan" kecil, tetapi mungkin sedikit biaya pada keterbacaan.
sumber
while(len > 0)
bukan!= -1
, karena yang terakhir juga bisa mengembalikan 0 saat menggunakanread(byte b[], int off, int len)
-metode, yang melempar pengecualian @out.write
InputStream
kontrak untuk dibaca untuk mengembalikan 0 beberapa kali. Dan menurutOutputStream
kontrak, metode menulis harus menerima panjang 0, dan hanya membuang pengecualian ketikalen
negatif.while
kefor
dan meletakkan salah satu variabel di bagian init untuk: misalnyafor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
,. =)read()
hanya dapat mengembalikan nol jika Anda memberikan panjang nol, yang akan menjadi kesalahan pemrograman, dan kondisi bodoh untuk mengulang selamanya. Danwrite()
tidak tidak membuang perkecualian jika Anda memberikan panjang nol.Menggunakan Jambu Biji
ByteStreams.copy()
:sumber
Files.copy
sebanyak mungkin. GunakanByteStreams.copy
hanya jika kedua aliran bukan FileInputStream / FileOutputStream.Fungsi sederhana
Jika Anda hanya memerlukan ini untuk menulis
InputStream
keFile
maka Anda dapat menggunakan fungsi sederhana ini:sumber
close()
panggilanfinally
?The
JDK
penggunaan kode yang sama sehingga tampak seperti tidak ada "lebih mudah" cara tanpa pihak ketiga perpustakaan kikuk (yang mungkin tidak melakukan apa-apa pula yang berbeda). Yang berikut disalin langsung darijava.nio.file.Files.java
:sumber
PipedInputStream
danPipedOutputStream
seharusnya hanya digunakan ketika Anda memiliki banyak utas, seperti dicatat oleh Javadoc .Juga, perhatikan bahwa aliran input dan aliran output tidak membungkus gangguan utas dengan
IOException
... Jadi, Anda harus mempertimbangkan untuk memasukkan kebijakan gangguan ke kode Anda:Ini akan menjadi tambahan yang berguna jika Anda berharap untuk menggunakan API ini untuk menyalin data dalam volume besar, atau data dari stream yang macet untuk waktu yang lama.
sumber
Bagi mereka yang menggunakan kerangka kerja Spring ada kelas StreamUtils yang berguna :
Di atas tidak menutup aliran. Jika Anda ingin stream ditutup setelah penyalinan, gunakan kelas FileCopyUtils sebagai gantinya:
sumber
Tidak ada cara untuk melakukan ini lebih mudah dengan metode JDK, tetapi seperti yang telah dicatat Apocalisp, Anda bukan satu-satunya yang memiliki gagasan ini: Anda dapat menggunakan IOUtils dari Jakarta Commons IO , ini juga memiliki banyak hal berguna lainnya, bahwa IMO harus benar-benar menjadi bagian dari JDK ...
sumber
Menggunakan Java7 dan coba-dengan-sumber daya , hadir dengan versi yang disederhanakan dan dapat dibaca.
sumber
Inilah yang saya lakukan dengan loop paling sederhana.
sumber
Gunakan kelas Util Commons Net:
sumber
Cuplikan IMHO lebih minimal (yang juga lebih sempit lingkup variabel panjang):
Sebagai catatan tambahan, saya tidak mengerti mengapa lebih banyak orang tidak menggunakan
for
loop, sebagai gantinya memilih untukwhile
dengan ekspresi assign-and-test yang dianggap oleh beberapa orang sebagai gaya "buruk".sumber
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Ini tembakan terbaik saya !!
Dan jangan gunakan
inputStream.transferTo(...)
karena terlalu generik. Kinerja kode Anda akan lebih baik jika Anda mengontrol memori buffer Anda.Saya menggunakannya dengan metode (improvisasi) ini ketika saya tahu sebelumnya ukuran stream.
sumber
Saya pikir lebih baik menggunakan buffer besar, karena sebagian besar file lebih besar dari 1024 byte. Juga merupakan praktik yang baik untuk memeriksa jumlah byte yang dibaca menjadi positif.
sumber
Saya menggunakan
BufferedInputStream
danBufferedOutputStream
menghapus semantik buffering dari kodesumber
PipedInputStream dan PipedOutputStream mungkin berguna, karena Anda dapat menghubungkan satu ke yang lain.
sumber
Kandidat lain yang mungkin adalah utilitas Jambu I / O:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Saya pikir saya akan menggunakan ini karena Guava sudah sangat berguna dalam proyek saya, daripada menambahkan perpustakaan lain untuk satu fungsi.
sumber
copy
dantoByteArray
metode di docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (jambu biji memanggil input / output stream sebagai "byte stream" dan pembaca / penulis sebagai "char streams")Tidak terlalu mudah dibaca, tetapi efektif, tidak memiliki dependensi dan berjalan dengan versi java apa pun
sumber
!= -1
atau> 0
? Predikat itu tidak persis sama.sumber
Coba Cactoos :
Lebih detail di sini: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
sumber
Anda dapat menggunakan metode ini
sumber
catch(Exception ex){}
- ini adalah yang terbaik