ついに夏本番!さぁ、家族でキャンプに行くぞ! >>

windows環境のクライアントPCにブラウザからファイルをダウンロードさせる
javaプログラムを作成しています。
linuxのサーバー側でcsvを圧縮したzipファイルを作成しているのですが
zipの作成処理までは速いのに、その後のファイル保存のダイアログに
とても時間がかかります。なぜなのか分からず困っています。


以下、保存ダイアログ表示のコードです。
---------------------------------------------
FileInputStream fi = new FileInputStream(ファイルパス/temp.zip);
byte[] b = new byte[fi.available()];
for (int i = 0; i < b.length; i++)
b[i] = (byte)fi.read();

response.setContentType("application/octet-stream; charset=Windows-31J");
response.setHeader("Content-Disposition","attachment; filename=\"temp.zip\"");
response.setContentLength(b.length);

ServletOutputStream os = response.getOutputStream();
os.write(b);
os.close();

fi.close();

---------------------------------------------
ご教授お願いします。

このQ&Aに関連する最新のQ&A

A 回答 (1件)

1バイトずつ読み込んでいる&全部読み込んでから送ってるので遅いのでしょう。


ブロック単位で読む&逐次送信するといいですよ。

File zipFile = new File("ファイルパス", "temp.zip");
response.setContentType("application/octet-stream; charset=Windows-31J");
response.setHeader("Content-Disposition","attachment; filename=\"temp.zip\"");
response.setContentLength(zipFile.length);
int len;
byte[] buf = new byte[1024];
InputStream is = new FileInputStream(zipFile);
ServletOutputStream os = response.getOutputStream();
while((len = is.read(buf)) >= 0){ // bufのサイズまで読み込む、実際に読んだ長さはlenに入る
os.write(buf, 0, len); // 読み込んだサイズ分送信する
}
is.close();
os.close();
    • good
    • 1
この回答へのお礼

早急なご回答有難うございます。
ご教授して頂いた方法に変更して実行してみました。
読み込みとレスポンス送信は1秒たらずでできるようになりました。
ただ、いまだにすぐにダイアログが表示されません。
os.close();の後は何も処理はしておらず、returnで戻してるだけなのですが・・・。

今回の環境と実行は、大量データがDBにある時かつ大量データの
抽出する目的でおこなっています。
データが少ない時は全く問題がありませんでした。
大量データのテストの時は、DBから抽出するのに3分→CSV作成に8分→
圧縮は1秒の過程です。でも、圧縮後のzpファイルは15kb程なので
ファイルが重過ぎることではないと思います。
なにか他に原因があるのでしょうか?

お礼日時:2011/04/23 06:46

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

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

下記のようなファイルの読み込み/書き込み処理において、もっと効率よく(速く)読み込み・書き込みをしたい場合どのような工夫をすれば良いでしょうか?

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();

Aベストアンサー

速くなるかどうかは環境によって微妙に違うと思いますが、効率よくやる方法が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());

速くなるかどうかは環境によって微妙に違うと思いますが、効率よくやる方法が2つあります。

1. 1バイトづつ読み書きするのではなくて byte[] で1000バイトとかの塊を読んでそのまま塊を書くようにする。(こうすると read, write をする回数が減るので少し速いと思います)。

2. FileInputStream と FileOutputStream のインスタンス双方から getChannel() で java.nio.channels.FileChannel のインスタンスを取り出し、FileOutputStream 側から取り出した FileChannel のインスタンスに対して transferFrom()...続きを読む

Qflush()とclose()について

Javaを独習Javaで独習しています。現在、入出力の所まできたのですが、Writerクラスのclose()とflush()の違いがわかりません。それぞれのメソッドの意味はわかるのですがそれらを使う目的がわかりません。flush()は「バッファ付けデータをそのストリームで表されている物理デバイスに書き込む」とあるのですが、サンプルには(バッファ付け文字ストリームの単元にも)flush()は一度も出てこずclose()のみで書き込みが行われています。探したのですが独習Javaのサンプルの中には結局flush()は一度も出てきませんでした。この二つの違いはなんなのでしょうか?初心者のためわかりにくい質問かとは思いますがよろしくお願いします。

Aベストアンサー

フラッシュすれば、ファイルやその他物理デバイスに強制的にバッファの内容が出力されるということは、理解されていると考えてよいですね?

で、なかなかストリームをクローズできない(またはしない)場合には、いつまで経ってもバッファの内容が物理デバイスに出力されないかも知れませんよね?でも、適当なタイミングで定期的にフラッシュすれば、その時点でバッファに溜まっている内容が物理デバイスに出力されます。

そのサンプルの場合は、書き出してすぐ?クローズしちゃうため、明示的なフラッシュは必要なかったんだと思いますが、

・フラッシュは、(ストリームを閉じずに)バッファの内容を強制的に物理デバイスに出力する。
・クローズは、(フラッシュされていなければフラッシュしてから)そのストリームを閉じる。

とまぁ、目的も内容も全然違うわけです。

QJavaでCSVファイルを高速に読む方法

最近、とある任務があって「数百万レコード」のCSVファイルを読み、
統計解析を実施するAPを自作したいと考えています。

しかし、ファイルのレコード数が膨大なため、解析する前にファイル読み込みに
大きな時間がかかってしまい困っています。

読み込みを高速化するために、複数のスレッドを用意し、スレッド毎に読みこむ
レコードの行を決めて、並列処理を行いたいと考えたのですが・・・

・任意の行をランダムに読むためRandomAccessFileクラスの利用を
 考えたがレコードが固定長でないと利用できない。

という点があり断念しています。私も詳しくはわかっていないのですがHadoopという
技術を使ってファイルを分割して並列処理するといった方法が取られているようですが
ファイルを高速に読み込む方法について、この質問を見ていただけた方の中で
こうすれば高速化できるというノウハウがもしあればご教授いただけるとありがたいです。

またできれば、複数の筐体にファイルを分割して分散処理するという大掛かりの手法ではなく、
一つの筐体で並列処理して高速化したいと考えています。

Javaは、あまり詳しくなくとんちんかんな質問かもしれませんがどうぞよろしくお願いします。

最近、とある任務があって「数百万レコード」のCSVファイルを読み、
統計解析を実施するAPを自作したいと考えています。

しかし、ファイルのレコード数が膨大なため、解析する前にファイル読み込みに
大きな時間がかかってしまい困っています。

読み込みを高速化するために、複数のスレッドを用意し、スレッド毎に読みこむ
レコードの行を決めて、並列処理を行いたいと考えたのですが・・・

・任意の行をランダムに読むためRandomAccessFileクラスの利用を
 考えたがレコードが固定長でないと利用できない。

...続きを読む

Aベストアンサー

Hadoopは大規模分散ファイルシステムであって、ファイルを分割して並列処理するというのとは違うみたいですが・・・

とりあえず私の思いついたのは読み込み専用スレッドを1つ用意しておいて順次解析用のスレッドを起動する方法かなぁ

QASPでCSVファイルを作成しダウンロードさせる

ASPファイルで、動的にCSVファイルを作成し、クライアントにダウンロードさせたいのですが、実際には、ファイルは作成せずに、ASPで直接、CSVフォーマットのファイルをダウンロードさせているように振舞わせることはできないでしょうか?

手順
クライアント        サーバー
あるURL(A.ASP)にアクセス
             A.ASPのスクリプトでCSVフォーマットを作成
             クライアントに送信(多分、Response.Writeで)
ダウンロードダイアログが開く
「A.CSVをダウンロードしますか?」
のような感じ
ダウンロード、またはExcelが開く

というようなイメージです。
CSVファイルを作ってしまうと、複数のユーザーからほぼ同時に要求があった場合、望むCSVにならない可能性があり、また、毎回ファイル名を変えると、Webサーバー上にCSVファイルが沢山できてしまうため、何とかこの方法でやりたいのですが、何かよい方法はありませんでしょうか?

ちなみに次のようなASPファイルをしてみましたが、うまくいきません。

<%
Response.Content-Type="application/vnd.ms-excel"
Response.Write "1,2" & vbNewLine
Response.Write "3,4" & vbNewLine
%>
また、「vnd.ms-excel」を「oct-stream」でもだめでした。
何かよい知恵をお貸しください。

ASPファイルで、動的にCSVファイルを作成し、クライアントにダウンロードさせたいのですが、実際には、ファイルは作成せずに、ASPで直接、CSVフォーマットのファイルをダウンロードさせているように振舞わせることはできないでしょうか?

手順
クライアント        サーバー
あるURL(A.ASP)にアクセス
             A.ASPのスクリプトでCSVフォーマットを作成
             クライアントに送信(多分、Response.Writeで)
ダウンロードダイアログが開く
「A.CSVをダ...続きを読む

Aベストアンサー

これでOK!です。

<%
Response.AddHeader "Content-disposition", "filename=""motteke.csv"""
Response.ContentType="text/csv"
Response.Write "1,2" & vbNewLine
Response.Write "3,4" & vbNewLine
%>

"text/csv"は適当です(笑)

Qsqlplusで表示が変なので、出力を整形したい。

いつもお世話になっています。

サーバにアクセスしてsqlplusで、
データを調べたいのですが、
出力形式が見づらくて困っています。

よくわからいのですが、
---------------------------
カラム名1
---------------------------
カラム名2
---------------------------
カラム名3
---------------------------
1の値 2の値
3の値
---------------------------
カラム名1
---------------------------
カラム名2
---------------------------
カラム名3
---------------------------

上記のように意味不明な形式で出てきます。

例えばこんな風に

select カラム1,カラム2,カラム3 from hoge;

カラム1 1の値
---------------------------
カラム2 2の値
---------------------------
カラム3 3の値

等のように分かりやすく表示できないでしょうか?

ちなみにOracle9iR2を使用しています。
sqlに関するツールは使用できないルールでして、あくまでsqlplusのコマンド上でみやすくしなければなりません。

分かりづらくですいませんが、皆さま、ご教授お願いします。

いつもお世話になっています。

サーバにアクセスしてsqlplusで、
データを調べたいのですが、
出力形式が見づらくて困っています。

よくわからいのですが、
---------------------------
カラム名1
---------------------------
カラム名2
---------------------------
カラム名3
---------------------------
1の値 2の値
3の値
---------------------------
カラム名1
---------------------------
カラム名2
---------------------------
カラム名3
-----------------------...続きを読む

Aベストアンサー

SQLPLUSを起動して、

SQL>set linesize 列数

でどうだ。

SQL>show linesize

で確認ができる。

QCSVファイルの中で、「 , 」カンマを使いたい

「 , 」で区切られたCSVファイルの中で、「 , 」カンマを使いたいのですが、可能でしょうか?

具体的には「これは1,500円でした。」というように、CSVファイルに収められた文章内で出てくる半角の数字(お金)の区切りに使いたいのです。
全角では代用したくないのですが、CSVファイルでデータを受け渡しする際に、困っています。

例えば、特殊文字などで対応可能でしょうか?

Aベストアンサー

受け渡しに使うと言うことは相手方のアプリケーションのことも考えなければいけないのですが・・・とりあえず対応が簡単そうな方法を。

1.各セルを""で囲む。(もちろんデータにダブルクォートがある場合はカンマと同様に困ります。
2.カンマで区切らずにタブで区切る。(比較的使われない文字ですが、やはりデータ中にタブがあるとカンマと同様です)

難しいけれど完璧に対応するためには、データ中の区切り文字は特殊な文字列に変更し、受け取り側のアプリケーションではその特殊な文字列をデータ中の区切り文字として扱うという方法が使われます。
例えば、データ中のカンマは\,にするとか。

データ作成側、受け取り側でそれぞれどこまで対応できるのか分かるともっと簡単かつ具体的な方法を回答できるかも知れません。

QIOException ってどういうときに起こるのでしょうか?

IOException ってどういうときに起こるのでしょうか?

http://www.atmarkit.co.jp/fjava/rensai2/javaent12/javaent12.html
を見て勉強しています。

  catch ( IOException e) {
    System.out.println( "キーボードが故障しているのかもしれません" );
  }

と書いてあります。
ハード(キーボード)が故障しているのを Java のプログラムのレベル(ソフトウェア)で感知できるというのがよくわかりません。「

NumberFormatException の方はわかるのですが・・・

Aベストアンサー

現実的には、キーボードからの入力でIOExceptionが発生することは、
ほとんどあり得ないと思います。
そもそも、キーボードが故障していたとしても、
IOExceptionは投げられないでしょう。
「キーボードが故障しているのかもしれません」というのは、
その記事の著者が冗談で書いたのだと思います。

ではなぜ、try-catchを書かなくてはいけないのか?
InputStreamやBufferedReaderは、
データ入力を抽象化したものだからです。
実際の入力元はキーボードだったり、ファイルだったり、
ネットワーク接続だったりするわけですけど、
InputStreamは、その入力元の情報を持っていないので、
データを読み取る際は常に
IOExceptionをキャッチするコードを書かなくてはいけません。
たとえ、絶対にIOエラーが発生しないストリームだとしても。

さらに付け加えるなら、
そもそも「標準入力=キーボード」であるとは限りません。
(一般的にはキーボードであることが多いですが。)
Javaでは、
System.setIn(InputStream)
を呼び出して、標準入力を変えてしまうことができますし、
標準入力を指定してプログラムを実行することができるOSもあります。

追伸1:
例外をキャッチしたときは、
スタックトレースをプリントすることをおすすめします。
catch (IOException e) {
e.printStackTrace();
}

追伸2:
そのプログラムでIOExceptionを発生させる最も簡単な方法は、
readLine()を呼び出す前に
標準入力(System.in)を閉じてしまうことです。
System.in.close();

現実的には、キーボードからの入力でIOExceptionが発生することは、
ほとんどあり得ないと思います。
そもそも、キーボードが故障していたとしても、
IOExceptionは投げられないでしょう。
「キーボードが故障しているのかもしれません」というのは、
その記事の著者が冗談で書いたのだと思います。

ではなぜ、try-catchを書かなくてはいけないのか?
InputStreamやBufferedReaderは、
データ入力を抽象化したものだからです。
実際の入力元はキーボードだったり、ファイルだったり、
ネットワーク接...続きを読む

QSELECTで1件のみ取得するには?

こんにちわ。
いまORACLE9iを使用している者です。

ACCESSでは
SELECT TOP 1 項目名 FROM テーブル名
ORDER BY 項目名;
で並べ替えたデータ群のうち,先頭の1件だけを
取ることができますが,
ORACLEでそのような機能(SQL)はあるでしょうか?
教えてください。
よろしくお願いします。

Aベストアンサー

order by と rownum を併用する場合は注意が必要です。

[tbl01]
cola | colb
------------
1000 | aaaa
1001 | bbbb

というデータがある場合、
select cola from tbl01 where rownum < 1 order by cola desc;
とすると、「1001」ではなく、「1000」が返されます。
これは、order by の前に rownum < 1 が適用されてしまうからです。

解決するには、
select aaa from (select cola aaa from tbl01 order by cola desc) where rownum = 1;
とすれば良いです。

Q期間の重複を調べるSQL文について・・・

EVENT
--+------------+------------+
id | start_date | end_date
--+------------+------------+
0 | 2007-06-01 | 2007-06-03 |
--+------------+------------+
1 | 2007-06-04 | 2007-04-06 |
--+------------+------------+
2 | 2007-06-02 | 2007-06-05 |

↑こんな感じでイベントを管理するテーブルがあります。
イベントの開催期間の重複を出力するSQL文を書きたいのですが、
何かいい案はありませんでしょうか???

結果的には重複し合っているレコードのidを出力させたいです。
よろしくお願いします。

Aベストアンサー

#3で提示したような結果でいいなら、下記SQLで実現できると思います。

select x.id,y.id as 重複id
from t1 as x,t1 as y
where
(x.sdate between y.sdate and y.edate
or x.edate between y.sdate and y.edate)
and x.id<>y.id
order by x.id,y.id;

QSQL文について(片方のテーブルに存在しないレコード抽出)

以下のような2つのテーブルがあったとして、
2つともに存在する「店コード」を抽出するのはSQLは分かるのですが、
片方に存在しない「店コード」(以下の例の場合、「2」)を抽出するSQLを
一文で書くにはどうすればいいのでしょうか?

<店テーブル>
店コード住所・・・(その他、基本情報)
1aaa
2bbb
3ccc

<販売テーブル>
店コード販売品目・・・(その他、販売数など)
1xxx
3zzz

Aベストアンサー

オプティマイザ次第だけど、NOT-INは、あまりお勧めでない。
外部結合も索引があっても有効に使われないので、お勧めでない。

select * from A where not exists(select 1 from B where A.店コード=B.店コード);


人気Q&Aランキング