- PR -

ファイルの作成について

投稿者投稿内容
saratoga
常連さん
会議室デビュー日: 2001/11/26
投稿数: 28
投稿日時: 2003-04-18 11:53
こんにちは。いつもお世話になっています。

現在、DBから取得した値をカンマ区切りのCSVファイルとして
ダウンロードさせる仕組みを考えています。

以下の方法で試してみようとしているのですが、うまくいきません。
@CSVを特定のフォルダに作成し、そのCSVに値を書き込んでいく。
ACSVのURLを取得し、変数に持たせる。
B変数のURLを呼び出し、クライアントにダウンロードさせる。

FileOutputStream()を利用してファイルの作成には成功しましたが、
特定のフォルダにファイルを作成する部分で詰まっています。
下記の場合、WINNT\System32の直下にファイルが出来上がってしまいます・・・。

(ソース)
PrintWriter out = new PrintWriter(new FileOutputStream("test.csv", true));

また、java.net.URLを用いてCSVのURLを取得し、
そのアドレスを呼ぼうと考えていますが、
URLを取ろうとすると、ローカルのパスが返ってきてしまいます。
私の考えでは、httpから始まるアドレスをServletから直接呼び出し、
クライアントにダウンロードのダイアログを表示させたいのです。

(ソース)
java.net.URL url =
getServletConfig().getServletContext().getResource("/csv/test.csv")
(結果)
D:\アプリケーションのパス/csv/test.csv

どなたか、このような実例が掲載されているサイトをご存知ないでしょうか?
ご教授よろしくお願いします。
keisuken
会議室デビュー日: 2003/04/18
投稿数: 4
投稿日時: 2003-04-18 12:53
とりあえず環境を書いておいたほうが良いですよ。(OS とか Servlet コンテナとか J2SDK のバージョン, クライアントのブラウザとか...)
ソースを見る限り Java Servlet だと思うので話を進めます。

まず動的に生成した CSV ファイルをユーザにダウンロードさせる方法として、

  1. いったんローカルにファイルを書き込んで URI を示しユーザにダウンロードしてもらう
  2. CSV ファイルをストリームとしてそのまま吐き出してしまう

前者はローカルディレクトリに直接書き込んでしまうため、場合によってはセキュリティに引っかかってしまうかもしれません(サーブレットコンテナのセキュリティモデルに依存します)。
後者がよさそうですが、ブラウザによって挙動が違うので、saratoga さんのおっしゃるとおり前者がいいでしょう。

引用:
下記の場合、WINNT\System32の直下にファイルが出来上がってしまいます・・・。

(ソース)
PrintWriter out = new PrintWriter(new FileOutputStream("test.csv", true));


これは相対パスでファイルを作っているので期待通りの動作ですね。この場合のカレントパスがたまたま %winnt%\system32 になっているだけでしょう。

引用:
(ソース)
java.net.URL url =
getServletConfig().getServletContext().getResource("/csv/test.csv")
(結果)
D:\アプリケーションのパス/csv/test.csv


これも期待通りの動作です。ServletContext#getResource(String path) で返される URL はローカルパスですのでご注意を。
ユーザに URI を返すのは相対パスで十分では?どこに作られるのかは上記のソースでわかるはずですからどうすればいいのかはわかりますよね?

しろう
会議室デビュー日: 2003/04/18
投稿数: 7
投稿日時: 2003-04-18 13:12
引用:

keisukenさんの書き込み (2003-04-18 12:53) より:
前者はローカルディレクトリに直接書き込んでしまうため、場合によってはセキュリティに引っかかってしまうかもしれません(サーブレットコンテナのセキュリティモデルに依存します)。
後者がよさそうですが、ブラウザによって挙動が違うので、saratoga さんのおっしゃるとおり前者がいいでしょう。



ファイル名が重複すると他のクライアントとバッティングすると思うのですが……ユニークなURIを取る仕組みが必要かと。
それにファイルを作成するって事は、パブリックなフォルダにリダイレクトするんですよね?
それもセキュリティモデル以前に、WEBシステムとしてのセキュリティ上の問題があるんじゃないんですか? 他にもファイルの生存期間とか気にしないといけないかもしれません。

この辺はsaratogaさんの求めているシステムがスタンドアロンで動けばよくて、自分ひとりが常に1ウインドウでしか使わないとかならいいのかも知れませんが。saratogaさんの作成しようとしているシステムの要求次第で仕様は変わるかと思います。

その辺の考慮を考えると、ServletのOutputStream処理の方が良いと思うのですが……。
それじゃこまる理由はなんでしょう?
saratoga
常連さん
会議室デビュー日: 2001/11/26
投稿数: 28
投稿日時: 2003-04-18 13:58
しろう様
keisuken様

こんにちは、早速の返事ありがとうございます。

現在の環境を書きます。(失礼しました)
OS:Windows2000 Server(SP2)
DBMS:SQL Server2000
JDK:1.3.0
J2EE:1.2.1
Servlet Engine:Unify eWave Engine

私がやろうとしていることは、
CSVを作成しクライアントにダウンロードさせることです。
私の勝手な想像かもしれませんが、
ファイルのダウンロードを動的に実行する場合は、
データを一旦ファイルに保存して、その場所を呼び出すと考えていました。
もしかして、ファイルを作成せずにユーザーにCSVを返すことが出来るのでしょうか?

私の構想(思い付く範囲)は以下の2通りです。

(構想1)
1.DBアクセスし、データをCSVファイルに書き込み。
(ファイル名はセッションIDや日時などを組み合わせた文字列)
2.次ページ(JSP)で作成したCSVにアクセス
(DownLoadボタンを作成し、FORMタグにCSVの直接アドレスを書きます)

(構想2)
1.DBアクセスし、データをCSVファイルに書き込み。
(ファイル名はセッションIDや日時などを組み合わせた文字列)
2.ServletからJSPではなく、CSVのアドレスを呼び出す

構想2の方が1回の処理で済むと思うのですが、
どちらの構想もCSVを作成するフォルダの指定ができなくて困ってます。
作成したい場所はJSPが置かれているフォルダ、
もしくは仮想ディレクトリを設けてそこに作ろうと思っています。

>keisuken様
>ユーザにURLを返すのは相対パスで十分では?

現在は%winnt%\system32になっていますが、
ここの変更方法はわかりません・・・。
環境設定のPathの設定のところでしょうか?
確かにここを変更できれば、思い通りのフォルダに作成できそうです。

お二方の意見を参考にして、いろいろ試してみます。
また、上記について助言がありましたらよろしくお願い致します。
しろう
会議室デビュー日: 2003/04/18
投稿数: 7
投稿日時: 2003-04-18 15:05
引用:

saratogaさんの書き込み (2003-04-18 13:58) より:

もしかして、ファイルを作成せずにユーザーにCSVを返すことが出来るのでしょうか?



出来ますよ(^o^)
HttpServletResponseのsetContentType()メソッドとsetHeader()を駆使すれば簡単かと思います。

このスレッドを頭から読めばでいくつかのサンプルもあって良いかと思います。
http://java-house.jp/ml/archive/j-h-b/040872.html

しかしいずれにせよ、一度CSVを作るのはセキュリティ上まずくないですか?
ネットワークのセキュリティポリシーに依存する所ですので、誰でもそのCSVファイルを見れる可能性がある事に問題が無ければよいと思いますけど。
この手の作業は作りこみよりセキュリティを気にした方が良いと思いますよ。外部からはどうにも出来ないですから(^-^;
しろう
会議室デビュー日: 2003/04/18
投稿数: 7
投稿日時: 2003-04-18 15:08
ごめんなさい。ちょっと不親切なURLでした……。

この辺が理解を深めるのに良いかと。
http://java-house.jp/ml/archive/j-h-b/040922.html
http://java-house.jp/ml/archive/j-h-b/040932.html
saratoga
常連さん
会議室デビュー日: 2001/11/26
投稿数: 28
投稿日時: 2003-04-18 15:51
しろう様

ありがとうございます。
setContentType()とsetHeader()を使ってヒントがつかめました。

response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "inline;filename=\"test.csv\"");

現状はダウンロードではなく、ブラウザにExcelの画面が開いてしまうので、
もう少し調査してダウンロードできる形にしていきたいと思います。

ご教授ありがとうございました。
教えていただいたサイトも今から見に行きたいと思います。
keisuken
会議室デビュー日: 2003/04/18
投稿数: 4
投稿日時: 2003-04-18 23:39
引用:

ファイル名が重複すると他のクライアントとバッティングすると思うのですが……ユニークなURIを取る仕組みが必要かと。
それにファイルを作成するって事は、パブリックなフォルダにリダイレクトするんですよね?
それもセキュリティモデル以前に、WEBシステムとしてのセキュリティ上の問題があるんじゃないんですか? 他にもファイルの生存期間とか気にしないといけないかもしれません。


うん、もちろんそれ(ユニークなディレクトリやファイル名(Session ID あたりを使えばいいのでしょう)、ファイルの生存期間)も重要なんですが、それ以前の話であったのであえてそこまで言及していません。まずファイルをローカルディレクトリに置けるかどうかが問題だと思います。Secure な話はその後です。
引用:

その辺の考慮を考えると、ServletのOutputStream処理の方が良いと思うのですが……。
それじゃこまる理由はなんでしょう?


もう私が書いたようにそれはブラウザによって挙動が違うからです。Internet Explorer が一般的だと思うのですが、ファイル名をブラウザに伝える部分でブラウザによっては上手く動かない可能性があるからです(たぶんファイル名が伝わらない)。ですから リダイレクトしてもらう or リンクを辿ってもらうという方式が確実ではありますね。イントラネットなどでブラウザを統一できる場合はこの限りではありません。

スキルアップ/キャリアアップ(JOB@IT)