• ベストアンサー

ファイル読み込み/書き込み速度を上げるには

下記のようなファイルの読み込み/書き込み処理において、もっと効率よく(速く)読み込み・書き込みをしたい場合どのような工夫をすれば良いでしょうか? BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("sample2.data")); BufferedInputStream in = new BufferedInputStream(new FileInputStream("sample1.data")); int c ; while((c = in.read()) != -1) { out.write(c); } in.close(); out.flush(); out.close();

  • Java
  • 回答数5
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

速くなるかどうかは環境によって微妙に違うと思いますが、効率よくやる方法が2つあります。 1. 1バイトづつ読み書きするのではなくて byte[] で1000バイトとかの塊を読んでそのまま塊を書くようにする。(こうすると read, write をする回数が減るので少し速いと思います)。 2. FileInputStream と FileOutputStream のインスタンス双方から getChannel() で java.nio.channels.FileChannel のインスタンスを取り出し、FileOutputStream 側から取り出した FileChannel のインスタンスに対して transferFrom() で FileInputStream 側から取り出した FileChannel のインスタンスを指定する。 例) in は FileInputStream のインスタンス, out が FileOutputStream のインスタンスの場合。 FileChannel fcin = in.getChannel(), fcout = out.getChannel(); fcout.transferFrom(fcin, 0, fcin.size());

その他の回答 (4)

  • unibon
  • ベストアンサー率47% (160/340)
回答No.5

> byte[] aa = new byte[10]; > while((c = in.read(aa)) != -1) > { > out.write(aa); > } このままだと、たとえば4バイトしか読んでいないのに10バイトを書いてしまい、お尻に6バイトのゴミが付いてしまいます。 変数 c に読めたバイト数が入りますので、これを書き込み時に使う必要があります。 out.write(aa, 0, c); とすれば良いです。 なお、バッファ処理を自前の配列を使ってやるのならば、 BufferedOutputStream/BufferedInputStream を使う必要はありません。FileOutputStream/FileInputStream をじかに使えば良いです。 しかし、自前の配列によるバッファと、BufferedOutputStream/BufferedInputStream のバッファを組み合わせて使っても、別段悪影響が出るわけではありません。

  • nfonfonfo
  • ベストアンサー率63% (12/19)
回答No.4

Javaにこだわらないならこういう方法もあります。 java.lang.Runtime,exec("copy sample1.data sample2.data"); まずボトルネックがどこかprofilerで計測してみては?

  • Bonjin
  • ベストアンサー率43% (418/971)
回答No.3

>out.write(aa); ではなくて out.write(aa, 0, c); です。 何故かはJavaDocを見て勉強して下さい。

  • unibon
  • ベストアンサー率47% (160/340)
回答No.2

Java の API の Buffered~ 系のクラスは、バッファーサイズのデフォルト値がとても小さいです。 BufferedInputStream や BufferedOutputStream は 8192 バイトのようです。 以前のバージョンだとさらに小さかったかもしれません。 BufferedInputStream も BufferedOutputStream も、コンストラクターの引数でバッファーサイズを指定できますので、メガバイト単位の大きな値を指定したほうが良いです。

renann
質問者

補足

noboru2000さんのアドバイスも加味して下記ソースコードにて実行したのですが、実行後のファイルサイズが下記のようになりました。 sample1.data   37,105,664 バイト(コピーもと) ↓ sample2.data   37,105,670 バイト(コピー) ファイルサイズが変わった原因はなんなのでしょうか。 コピーもとのファイルはバイナリの画像ファイルです。 コピー後のファイルに破損はありませんでした(正常に画像が表示されました)。 <ソースコード> import java.io.*; class IO_Test { public static void main(String args[]) { try { BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("sample2.data"),1000000); BufferedInputStream in = new BufferedInputStream(new FileInputStream("sample1.data"),1000000); int c ; byte[] aa = new byte[10]; while((c = in.read(aa)) != -1) { out.write(aa); } in.close(); out.flush(); out.close(); } catch(Exception e) { e.printStackTrace(); } } }    

関連するQ&A

  • socketでのバイナリファイルの扱い方

    javaのsocketを用いてファイルの送信サーバ、受信クライアントを作成しているのですが テストプログラムとしてスレッド化せずに送信・受信部のみ作りました。 症状はバイナリデータの転送がうまくできないことです。ソースを抜粋すると サーバ側で BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());//socketはSocketクラス BufferedInputStream in1 = new BufferedInputStream( new FileInputStream("test1.bmp")); BufferedInputStream in2 = new BufferedInputStream( new FileInputStream("test2.bmp")); while( (c = in1.read() ) != -1 ){   out.write(c); } while( (c = in2.read() ) != -1 ){   out.write(c); } クライアント側で BufferedOutputStream out1 = new BufferedOutputStream( new FileOutputStream("test1.out.bmp") ); BufferedOutputStream out2 = new BufferedOutputStream( new FileOutputStream("test2.out.bmp") ); BufferedInputStream in = new BufferedInputStream( s.getInputStream() ); while( ( c=in.read() ) != -1 ){   out1.write(c); } while( ( c=in.read() ) != -1 ){   out2.write(c); } とやっています。 クライアント側で1回目のin.readを抜けるときにはサーバ側は既に2回のwriteを終わっているようで ファイルはtest1.out.bmpにマージされていました。 サーバ側の1回目のwriteのオブジェクトがcloseしていないことが原因だと思い1回目のwriteが終わった時点でout.close()とした のですがそうやるとsocketも閉じてしまいsocket closeのエラーが生じてしまいました。 このようにならず1本のコネクションでバイナリのデータを複数送信する方法をご存知でしたら教えてください。 [環境] win2ksp1a,j2sdk1.4.1_03,java経験4ヶ月程度

  • バイナリファイルを転送したいのですが

    お世話になります socketを用いてサーバへファイルを転送したいのですが、うまくいきません。 以下ソースからの抜粋です BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream()); BufferedInputStream in = new BufferedInputStream(new FileInputStream("test.txt")); int c; while((c = in.read()) != -1 ){  out.write(c); } 上記のようなコーディングでは転送できないのでしょうか? 出来ればファイルから1024バイトずつ読み込んで1024バイトずつ出力していき、ファイルの終端まで繰り返す処理をしたいのですが、よい方法をご存知でしたら教えていただけないでしょうか?

    • ベストアンサー
    • Java
  • 固定長データのbyteスキップについて

    バイナリ入出力でご質問がございます。 下記の例のように各レコードにある 先頭5byte付与されたデータを スキップ(破棄)して 各レコード10byteずつ読み込みたいのですが なにかサンプルデータもしくは アドバイス頂けないでしょうか? どうぞよろしくお願い致します。 例 1レコード 10byte (先頭5byte付与) LLLLL1234567890 LLLLL1234567890 LLLLL1234567890 LLLLL1234567890 LLLLL1234567890 ↓ 1234567890 1234567890 1234567890 1234567890 1234567890 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.io.ByteArrayOutputStream; public class dat{ public static void main(String[] args) { String inputFileName = ""; String outputFileName = ""; // ファイルオブジェクトの生成 File inputFile = new File(inputFileName); File outputFile = new File(outputFileName); try { FileInputStream fis = new FileInputStream(inputFile); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bos = new BufferedOutputStream(fos); byte[] buf = new byte[17]; int len = 0; while ((len = bis.read(buf, 0, 17)) == 17) { bos.write(buf, 0, 17); } bos.flush(); bos.close(); bis.close(); } catch(Exception e) { e.printStackTrace(); } }

    • ベストアンサー
    • Java
  • ファイル転送が正常に動作しない

    サーバ側からクライアント側へファイル転送をJavaで行おうとしています。 そこで以下のようなプログラムを作成し、実行するのですが 実行自体はうまくいき、1つめのファイルはきちんと転送できるのですが、 2つめのファイルが転送完了後に確認すると0バイトとなっており、 きちんと動作しません。どうするべきでしょうか。 サーバ側 ※上でソケットはつないであります。 if(command.equals("put.") == true){ System.out.println("putモードに入りました"); // カーネル(linux.uml)の送信 String filename1 = args[1]; byte[] data1 = new byte[1024]; //ストリームの作成 FileInputStream fin1= new FileInputStream(filename1); BufferedOutputStream out2 = new BufferedOutputStream(sock.getOutputStream()); System.out.println("送信ファイル : " + filename1); //int totalSize1 = 0; int len1; while((len1 = fin1.read(data1)) != -1){ out2.write(data1); } out.flush(); fin1.close(); System.out.println(filename1 + "を送信完了しました"); // ルートファイルシステム(uml-root-hardy)の送信 String filename2 = args[2]; byte[] data2 = new byte[1024]; //ストリームの作成 FileInputStream fin2 = new FileInputStream(filename2); //ファイルの内容を読み出し、送信する System.out.println("送信ファイル" + filename2); //long totalSize2 = 0; long len2 = 0; while((len2 = fin2.read(data2)) != -1){ out2.write(data2); } out.flush(); fin2.close(); System.out.println(filename2 + "を送信完了しました"); } クライアント側 ※上でソケットはつないであります。 if(change.equals("put.") == true){ System.out.println("putモードに入りました"); // 2つのファイルを転送する // カーネル(linux.uml)の転送 String filename1 = args[2]; System.out.println("受信するファイル : " + filename1); // FileOutputStreamの作成 FileOutputStream fout1 = new FileOutputStream(filename1); BufferedInputStream in2 = new BufferedInputStream(sock.getInputStream()); int recvMsgSize1; int bufSize = 1024; byte[] byteBuffer1 = new byte[bufSize]; //int totalByte1 = 0; while((recvMsgSize1 = in2.read(byteBuffer1)) != -1){ fout1.write(byteBuffer1); } System.out.println(filename1 + "を受信完了しました"); fout1.close(); // ルートファイルシステム(uml-root-hardy)の転送 String filename2 = args[3]; System.out.println("受信するファイル : " + filename2); FileOutputStream fout2 = new FileOutputStream(filename2); long recvMsgSize2; //byte[] byteBuffer = new byte[bufSize]; byte[] byteBuffer2 = new byte[bufSize]; //long totalByte2 = 0; while((recvMsgSize2 = in2.read(byteBuffer2)) != -1){ fout2.write(byteBuffer2); } System.out.println(filename2 + "を受信完了しました"); fout2.close(); } またプログラム中では、サーバ、クライアントでそれぞれ len1,len2(サーバ側)、recvMsgSize1,recvMsgSize2(クライアント側) に警告で「ローカル変数len1(recvMsgSize1)は読み取られません」 と出ています。 どのように解決するべきでしょうか。

    • ベストアンサー
    • Java
  • レコード長からのbyteスキップ設定について

    QNo.8229324から あらたに新規でご質問させて頂きます。 1レコードごとに10byteあったとします。 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 レコード長からスキップ設定を35byteと設定したとします。 40byteごとに頭の付与された5byteをスキップさせたいのですが なにかサンプル及びアドバイス頂けますでしょうか? 仕様案 (1)まずはレコード先端の5byteをスキップ (2)次は35byteを超えた時点で5byteスキップを繰り返し。 どうぞ宜しくお願い致します。 import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.io.ByteArrayOutputStream; public class dat{ public static void main(String[] args) { String inputFileName = ""; String outputFileName = ""; // ファイルオブジェクトの生成 File inputFile = new File(inputFileName); File outputFile = new File(outputFileName); try { FileInputStream fis = new FileInputStream(inputFile); BufferedInputStream bis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream(outputFile); BufferedOutputStream bos = new BufferedOutputStream(fos); byte[] buf = new byte[17]; int len = 0; while ((len = bis.read(buf, 0, 17)) == 17) { bos.write(buf, 0, 17); } bos.flush(); bos.close(); bis.close(); } catch(Exception e) { e.printStackTrace(); } }

    • ベストアンサー
    • Java
  • バイナリファイルの読み込みについて

    java初心者です。 今バイナリファイルの読み込みを行っているのですがバイナリファイルのデータの値とプログラムで読み込んだ値が違っているので困っています。 バイナリファイルはASCIIテキストになっていてデータを見ることができ中身は -0.00012 -0.00009 -0.00009 -0.00012 -0.00009 -0.00009 -0.00009 -0.00012 ・・・・・・・(値が続くという意味です) となっています。 作ったプログラムは import java.io.*; class a { public static void main(String[] args) { try { FileInputStream in = new FileInputStream("file name"); int ch; while ((ch = in.read()) != -1) { System.out.println(ch); } in.close(); } catch (IOException e) { System.out.println(e); } } } で作って読み込んでみたのですが出力された値は 45 48 46 48 48 48 49 50 ・・・・・・ になってしまいます。 どのようにしたら値が等しくなるのでしょうか。教えてください。

    • ベストアンサー
    • Java
  • ソケットプログラミングについて

    こんにちは。 前回、質問しました「バード」という者です。 ソケットプログラミングについて質問します。 PC1から、jpegやmpegファイルを送信しPC2で受信するというプログラムをC言語で作ってみたいと思っています。 以前、少しだけJAVAプログラミングでPC1(送信側)からPC2(受信側)へデータを送信するプログラムを作ったのですが、作ったプログラムの概要を以下に示します。 [送信側] (ファイルオープン) InputStream in = new FileInputStream(ss); BufferedInputStream bin = new BufferedInputStream(in); ↓ (データを読みsendメソッドにて随時送信) while((c = bin.read(buffer, 0, buffer.length))!=-1){ dPacket = new DatagramPacket(buffer,buffer.length,iAddress,port); dSocket.send(dPacket); } ↓ (ファイルとソケットクローズ) dSocket.close(); [受信側] (ファイルオープン) OutputStream out = new FileOutputStream(args[1]); BufferedOutputStream bout = new BufferedOutputStream(out); ↓ (送信側から来たデータをreceiveメソッドにて受信) while(true){ dPacket = new DatagramPacket(buffer,buffer.length); dSocket.receive(dPacket); } ↓ (ファイルとソケットクローズ) dSocket.close(); 上記に示す様に、ファイルをオープンし、DatagramSocketとDatagramPacketクラスを用いて送受信し最後に、ファイルをクローズするという形式をとっていました。 C言語の場合でも、ファイルオープン→send関数,receive関数等を用いて送信・受信→ファイルクローズという形をとる事ができるのでしょうか?FTPプログラムやエコープログラムを、よく見かけるのですが・・・・

  • UNICODEへの文字コード変換

    以下のようにして、 日本語で書かれたファイルを読み込んで、 UNICODEに変換したいのですが、 できません。。。 どこが間違っているのでしょうか?(;;) 元の日本語ファイル「こんにちは」 >>できたファイル「\u3053\u3093\u306b\u3061\u306f」 という風にしたいのですが。。 //FileIOSteramの作成 FileInputStream fis = new FileInputStream(iFile); FileOutputStream fos = new FileOutputStream(oFile); //Stream ラップ InputStreamReader in = new InputStreamReader(fis, "EUC-JP-LINUX"); OutputStreamWriter out = new OutputStreamWriter(fos, "UTF16"); System.out.println(System.getProperty("file.encoding")); //読み込みと書き込み int c; InputStreamReader in = new InputStreamReader(fis, "Unicode"); Writer out = new Writer(fos); while((c = in.read()) != -1){ out.write(c); }

  • ストリームの問題について【至急】

    import java.io.*; public class FileStreamDemo { public static void main(String[] args){ try{ byte[] buffer=new byte[1024]; FileInputStream fileInputStream= new FileInputStream(new File(args[0])); FileOutputStream fileOutputStream= new FileOutputStream(new File(args[1])); System.out.println("コピーファイル: "+fileInputStream.available()+"バイト"); while(true){ if(fileInputStream.available()<1024){ int remain=-1; while((remain=fileInputStream.read())!=-1){ fileOutputStream.write(remain); } break; } else{ fileInputStream.read(buffer); fileOutputStream.write(buffer); } } fileInputStream.close(); fileOutputStream.close(); System.out.println("コピー完了"); } catch(ArrayIndexOutOfBoundsException e){ System.out.println( "using:java FileStreamDemo src des"); e.printStackTrace(); } catch(IOException e){ e.printStackTrace(); } } } JAVAの入門者です。 JAVAの教科書に書いてあるように、上のプログラムを書きましたけど… コンパイルすると、エラーメッセージが出て来ます。 エラー中身は下記のとおりです。 【using:java FileStreamDemo src des java.lang.ArrayIndexOutOfBoundsException: 0 at FileStreamDemo.main(FileStreamDemo.java:8) 】 どうすればいいのか悩んでいます。 誰か、助けていただけないのでしょうか?どこか間違ってるか、教えてください。 よろしく、お願いします。

  • ファイル書き込みに関して

    FileOutputStream fos = new FileOutputStream("test"); OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8"); out.write("なに"); out.close(); fos.close(); 以上のコードを実行させて、ファイルtestをUTF8で開いたら、文字化けしています。どう直したらいいですか?

    • ベストアンサー
    • Java