3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ClojureからWindowsの共有ファイル(CIFS)にjcifsを使用してアクセスする

Last updated at Posted at 2012-05-21

==========

Windowsとの連携で必要となったのでメモ

OSに非依存な方法としてjcifsは今のところ良い方法と思う
win-win間、Linux-win間でのファイルアクセスを確認した

jcifsの利用

mavenレポジトリに存在するので
(http://mvnrepository.com/artifact/jcifs/jcifs を参照)
leiningenを使ってインストールする。
現時点(2012.4)で最新版は1.3.17なので
project.cljはこんな感じ

project.clj
(defproject jcifsample "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [jcifs "1.3.17"]]
  :dev-dependencies [[swank-clojure "1.4.1"]]
  )

あとは

lein desp

を実行

サンプルコード

import & useする関数群

使用するjava.ioまわりとjava.util.Propertiesを指定してimport & useする
java.ioは必要なものだけを取り込めばOK(サンプルは多めに指定している)
jcif.smbまわりとjcifs Configを指定する
jcif.smbも必要なものだけを取り込めばOK


(use '(clojure.java.io))
(import
   [java.io FileReader BufferedReader PushbackReader FileInputStream File
    FileOutputStream InputStreamReader PrintWriter OutputStreamWriter]
   [java.util Properties]
   [jcifs.smb SmbFileInputStream SmbFile SmbFileOutputStream]
   [jcifs Config]
   )

CIFSファイル共有の設定

PropertiesにID,PASSをハードコードしているがセキュリティ上はよろしくないので、実際にはセキュリティ要件に合せて実装のこと(実行時にユーザに入力してもらうID,PASSを利用する、ID,PASSを保存する場合は暗号化を施す等)

アクセスするWindowsの指定とテキスト形式で読み込む場合のエンコードを指定


;; PropertiesにwindowsでアクセスするユーザID,パスワードを設定
(def prop (Properties.))
(.setProperty prop "jcifs.smb.client.username", "{USER IDを指定}")
(.setProperty prop "jcifs.smb.client.password", "{上記で指定したUSER IDのパスワード}")
(Config/setProperties prop)

;;共有するサーバ、フォルダを指定
(def *test_serv* "smb://{Windowsのコンピュータ名}/{共有フォルダ名}/")

以降のサンプルは上記で定義した*test_serv*を利用する

サーバ上あるファイルをテキストとして読む

バイナリとして普通に読み込む場合は
smbFileInputStreamのインスタンスを作成してreadで読み込む

サーバ上ある"新しいテキスト ドキュメント.txt"をテキストとして読む(エンコードはsjis)


(->
	(SmbFileInputStream. (str *test_serv* "新しいテキスト ドキュメント.txt"))
    (InputStreamReader. "Shift_JIS")
    (BufferedReader.)
    read-lines)

ファイル一覧の取得

listFilesで共有しているファイル、ディレクトリの一覧をSmbFileオブジェクトとして取得

(.listFiles (SmbFile. *test_serv*))

listで共有しているファイル、ディレクトリの一覧をファイル名、ディレクトリ名で所得

(.list (SmbFile. *test_serv*))

ファイルのみを取得する

(filter #(.isFile %)
	(.listFiles (SmbFile. *test_serv*)))

ファイルのコピー

ファイルのコピーはclojureのcopy関数が利用できる
ただしアクセス権限の属性はファイルシステムにより異るためコピー出来無い
コピー先のファイルにあわせ再度設定する必要がある

リモート-ローカル間の例

リモート-ローカル間のファイルコピーの例(コピー先は実行時のカレントディレクトリ)

(with-open [i (SmbFileInputStream. (str *test_serv* "{コピー元ファイル名}"))
		    o (FileOutputStream. (str "./{コピー先ファイル名}"))]
   (copy i o))

リモート-ローカル間のファイルの一括コピー例(コピー先は実行時のカレントディレクトリ)
コピー元のフォルダからファイル(隠し属性は除く)のみを一括コピー

(for [f
      (filter #(and (.isFile %) (not (.isHidden %)))
              (.listFiles (SmbFile. *test_serv*)))]
  (with-open [i (SmbFileInputStream. f)
              o (FileOutputStream. (str "./" (.getName f)))]
    (copy i o)))

リモート-リモート間の例

リモートにサーバ上にコピー先のフォルダをtestという名前で作成しこのディレクトリをコピー先に指定する

(.mkdir (SmbFile. (str *test_serv* "test/")))

以降のサンプルでは上記で作成したtestディレクトリにコピーすることとする

リモート-リモート間のファイルコピーの例

(with-open [i (SmbFileInputStream. (str *test_serv* "{コピー元ファイル名}"))
		    o (SmbFileOutputStream. (str *test_serv* "/test/{コピー先ファイル名}"))]
   (copy i o))

リモート-リモート間のファイルの一括コピー(リモートのtestフォルダに一括コピー)
コピー元のフォルダからファイル(隠し属性は除く)のみを一括コピー

(for [f
      (filter #(and (.isFile %) (not (.isHidden %)))
              (.listFiles (SmbFile. *test_serv*)))]
  (with-open [i (SmbFileInputStream. f)
              o (SmbFileOutputStream. (str *test_serv* "/test/" (.getName f)))]
    (copy i o)))
3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?