001package org.opengion.fukurou.model; 002 003import java.io.ByteArrayInputStream; 004import java.io.ByteArrayOutputStream; 005import java.io.File; 006import java.io.FileNotFoundException; 007import java.io.IOException; 008import java.io.InputStream; 009import java.util.ArrayList; 010import java.util.List; 011 012import org.opengion.fukurou.util.Closer; 013import org.opengion.fukurou.util.HybsFileFilter; 014import org.opengion.fukurou.util.StringUtil; 015 016/** 017 * ファイル操作の抽象クラス 018 * 019 * 共通の処理等を実装しています。 020 * 021 * @og.group ファイル操作 022 * 023 * @og.rev 5.10.8.0 (2019/02/01) 新規作成 024 * @og.auth oota 025 * @since JDK7.0 026 */ 027public abstract class AbstractFileOperation implements FileOperation { 028 029 /* クラス定数 */ 030 private static final int BUFFER_SIZE = 1024 * 4; 031 /* クラス変数 */ 032 // パス 033 protected final String path; 034 // バケット名 035 protected final String bucket; 036 037 /** 038 * コンストラクタ 039 * ローカルサーバ用 040 */ 041 public AbstractFileOperation() { 042 path = ""; 043 bucket = ""; 044 } 045 046 /** 047 * コンストラクタ 048 * クラウドストレージ用 049 * 050 * @param buket バケット 051 * @param inPath パス 052 */ 053 public AbstractFileOperation(final String buket , final String inPath) { 054 path = editPath(replaceFileSeparetor(inPath)); 055 this.bucket = buket; 056 057 if (StringUtil.isNull(bucket)) { 058 String errMsg = "バケット未指定です。hayabusa利用ではシステム変数の「CLOUD_BUCKET」にバケット名を設定して下さい。"; 059 throw new RuntimeException(errMsg); 060 } 061 } 062 063 /** 064 * InputStreamのデータを書き込みます。 065 * 066 * @param is 書き込みデータのInputStream 067 * @throws IOException 068 */ 069 @Override 070 public void write(InputStream is) throws IOException { 071 String errMsg = "このクラスでは実装されていません。write(InputStream is)"; 072 throw new UnsupportedOperationException(errMsg); 073 } 074 075 /** 076 * データを読み込み、InputStreamとして、返します。 077 * 078 * @return 読み込みデータのInputStream 079 * @throws FileNotFoundException 080 */ 081 @Override 082 public InputStream read() throws FileNotFoundException { 083 String errMsg = "このクラスでは実装されていません。read()"; 084 throw new UnsupportedOperationException(errMsg); 085 } 086 087 /** 088 * ファイルを削除します。 089 * 090 * @return 成否フラグ 091 */ 092 @Override 093 public boolean delete() { 094 String errMsg = "このクラスでは実装されていません。delete()"; 095 throw new UnsupportedOperationException(errMsg); 096 } 097 098 /** 099 * ファイルを指定先に、コピーします。 100 * 101 * @param afPath コピー先 102 * @return 成否フラグ 103 */ 104 @Override 105 public boolean copy(String afPath) { 106 String errMsg = "このクラスでは実装されていません。copy(String)"; 107 throw new UnsupportedOperationException(errMsg); 108 } 109 110 /** 111 * ファイルを指定先に、移動します。 112 * 113 * @param afPath 移動先 114 * @return 成否フラグ 115 */ 116 @Override 117 public boolean move(String afPath) { 118 boolean flgRtn = false; 119 120 flgRtn = copy(afPath); 121 if (flgRtn) { 122 flgRtn = delete(); 123 } 124 125 return flgRtn; 126 } 127 128 /** 129 * 設定パスを取得します。 130 * 131 * @return 設定パス 132 */ 133 @Override 134 public String getPath() { 135 return path; 136 } 137 138 /** 139 * 絶対パスを取得します。 140 * 141 * @return 絶対パス 142 */ 143 @Override 144 public String getAbsolutePath() { 145 return path; 146 } 147 148 /** 149 * 名称を取得します。 150 * 151 * @return 名称 152 */ 153 @Override 154 public String getName() { 155 return drawName(path); 156 } 157 158 /** 159 * 親のパスを取得します。 160 * 161 * @return 親のパス 162 */ 163 @Override 164 public String getParent() { 165 return drawParent(path); 166 } 167 168 /** 169 * ファイルサイズを返します 170 * 171 * @return ファイルサイズ 172 */ 173 @Override 174 public long length() { 175 // TODO 自動生成されたメソッド・スタブ 176 return 0; 177 } 178 179 /** 180 * 最終更新時刻を取得します。 181 * 182 * @return 最終更新時刻 183 */ 184 @Override 185 public long lastModified() { 186 // TODO 自動生成されたメソッド・スタブ 187 return 0; 188 } 189 190 /** 191 * ファイルの場合は、trueを返します。 192 * 193 * @return ファイルフラグ 194 */ 195 @Override 196 public boolean isFile() { 197 // TODO 自動生成されたメソッド・スタブ 198 return false; 199 } 200 201 /** 202 * ディレクトリの場合は、trueを返します。 203 * 204 * @return ディレクトリフラグ 205 */ 206 @Override 207 public boolean isDirectory() { 208 // TODO 自動生成されたメソッド・スタブ 209 return false; 210 } 211 212 /** 213 * 存在する場合は、trueを返します。 214 * 215 * @return 存在フラグ 216 */ 217 @Override 218 public boolean exists() { 219 return isDirectory() | isFile(); 220 } 221 222 /** 223 * パスのファイルとディレクトリ一覧を取得します。 224 * 225 * @return ファイルとティレクトリ一覧 226 */ 227 @Override 228 public FileOperation[] listFiles() { 229 return listFiles(new HybsFileFilter()); 230 } 231 232 /** 233 * パスのファイルとディレクトリ一覧を取得して、 234 * 引数でフィルターを行います。 235 * 236 * @param filter フィルター 237 * @return ファイルとディレクトリ一覧 238 */ 239 @Override 240 public FileOperation[] listFiles(FileOperationFileFilter filter) { 241 String errMsg = "このクラスでは実装されていません。listFiles(FileOperationFileFilter)"; 242 throw new UnsupportedOperationException(errMsg); 243 } 244 245 /** 246 * ディレクトリを作成します。 247 * 248 * ※1つのディレクトリのみ作成します。 249 * (クラウドストレージにはディレクトリの概念が無いため、 250 * 作成は行わず、trueを返します) 251 * 252 * @return 成否フラグ 253 */ 254 @Override 255 public boolean mkdir() { 256 return true; 257 } 258 259 /** 260 * ディレクトリを作成します。 261 * 262 * ※複数のディレクトリを作成します。 263 * (クラウドストレージにはディレクトリの概念が無いため、 264 * 作成は行わず、trueを返します) 265 * 266 * @return 成否フラグ 267 */ 268 @Override 269 public boolean mkdirs() { 270 return true; 271 } 272 273 /** 274 * 指定のファイル情報のファイル名に変更します。 275 * 276 * @param dest 変更後のファイル情報 277 * @return 成否フラグ 278 */ 279 @Override 280 public boolean renameTo(FileOperation dest) { 281 return move(dest.getPath()); 282 } 283 284 /** 285 * 親のディレクトリを返します。 286 * 287 * @return 親のディレクトリ 288 */ 289 @Override 290 public FileOperation getParentFile() { 291 return null; 292 } 293 294 /** 295 * 書き込み可能フラグ 296 * 297 * ※クラウドストレージの場合は、 298 * 必ずtrueを返します。 299 * 300 * @return 書き込み可能フラグ 301 */ 302 @Override 303 public boolean canWrite() { 304 return true; 305 } 306 307 /** 308 * 読み取り可能フラグ 309 * 310 * ※クラウドストレージの場合は、 311 * 必ずtrueを返します。 312 * 313 * @return 読み取り可能フラグ 314 */ 315 @Override 316 public boolean canRead() { 317 return true; 318 } 319 320 /** 321 * 隠しファイルフラグ 322 * 323 * ※クラウドストレージの場合は、 324 * 必ずfalseを返します。 325 * 326 * @return 隠しファイルフラグ 327 */ 328 @Override 329 public boolean isHidden() { 330 return false; 331 } 332 333 /** 334 * 新規ファイル作成 335 * 336 * 既にファイルが存在しない場合のみ、 337 * 空のファイルを作成します。 338 * 339 * @return 成否フラグ 340 * @throws IOException 341 */ 342 @Override 343 public boolean createNewFile() throws IOException { 344 boolean rtn = false; 345 346 if (!exists()) { 347 InputStream is = null; 348 try { 349 is = new ByteArrayInputStream(new byte[0]); 350 write(is); 351 rtn = true; 352 } finally { 353 Closer.ioClose(is); 354 } 355 } 356 357 return rtn; 358 } 359 360 /** 361 * 最終更新時刻の更新 362 * 363 * 最終更新時刻の更新を行います。 364 * ※クラウドストレージの場合は、 365 * 最終更新時刻の更新を行えません。 366 * 367 * @param time 更新する最終更新時刻 368 * @return 成否フラグ 369 */ 370 @Override 371 public boolean setLastModified(long time) { 372 // クラウドストレージでは、setLastModifiedによる、 373 // 最終更新時刻の設定はできないので、 374 // 処理を行わずにtrueを返します。 375 return true; 376 } 377 378 /** 379 * カノニカルファイル情報の取得 380 * 381 * ※ローカルサーバのみ通常ファイルと、 382 * カノニカルファイルで異なります。 383 * 384 * @return カノニカルファイル情報 385 * @throws IOException 386 */ 387 @Override 388 public FileOperation getCanonicalFile() throws IOException { 389 return this; 390 } 391 392 /** 393 * toStringメソッド 394 * パスを返します。 395 */ 396 @Override 397 public String toString() { 398 return path; 399 } 400 401 /** 共通関数 **/ 402 /** 403 * ファイルパスの編集 2018/05/07 ADD 404 * パスの先頭が「/」の場合は「/」の除去と、「//」を「/」に置換処理の追加。 405 * 406 * @og.rev 5.9.32.1 (2018/05/11) 407 * @param path 408 * @return 変更後パス 409 */ 410 protected String editPath(final String path) { 411 if (StringUtil.isNull(path)) { 412 return ""; 413 } 414 415 String rtn = path; 416 // 先頭が「/」の場合は除去 417 if ("/".equals(rtn.substring(0, 1))) { 418 rtn = rtn.substring(1); 419 } 420 // 「//」は「/」に置換 421 rtn = rtn.replaceAll("//", "/"); 422 // 後尾の「.」は除去 423 rtn = rTrim(rtn, '.'); 424 // 後尾の「/」は除去 425 rtn = rTrim(rtn, '/'); 426 427 return rtn; 428 } 429 430 /** 431 * キーから親のパスを抽出します。 432 * 433 * @param key キー 434 * @return 親のパス 435 */ 436 protected String drawParent(String key) { 437 int k = key.lastIndexOf("/"); 438 439 String rtn = ""; 440 if (k > 0) { 441 rtn = key.substring(0, key.lastIndexOf("/")); 442 } 443 if ("/".equals(File.separator)) { 444 rtn = File.separator + rtn; 445 } 446 447 return rtn; 448 } 449 450 /** 451 * 引数のkeyから名称を抽出します。 452 * 453 * @param key キー(パス) 454 * @return 名称 455 */ 456 protected String drawName(String key) { 457 int k = key.lastIndexOf("/"); 458 459 String rtn = key; 460 if (k > 0) { 461 rtn = key.substring(key.lastIndexOf("/") + 1); 462 } 463 return rtn; 464 } 465 466 /** 467 * 後尾に「/」がない場合は、付与します。 468 * 469 * @param path パス 470 * @return 後尾に「/」ありのパス 471 */ 472 protected String setDirTail(String path) { 473 if (StringUtil.isNull(path)) { 474 return path; 475 } 476 477 StringBuilder sb = new StringBuilder(path); 478 if (!"/".equals(path.substring(path.length() - 1))) { 479 sb.append("/"); 480 } 481 return sb.toString(); 482 } 483 484 /** 485 * 右側の文字が、指定の文字の場合、除去します。 486 * 487 * @param str 対象文字列 488 * @param chr 指定文字 489 * @return 右側から指定文字を除去後の文字列 490 */ 491 protected String rTrim(final String str, char chr) { 492 String rtn = str; 493 int trgPos = 0; 494 for (int i = str.length() - 1; i >= 0; i--) { 495 if (str.charAt(i) == chr) { 496 trgPos = i; 497 // すべて合致した場合は、から文字を返す 498 if (trgPos == 0) { 499 rtn = ""; 500 } 501 } else { 502 break; 503 } 504 } 505 506 if (trgPos > 0) { 507 rtn = str.substring(0, trgPos); 508 } 509 510 return rtn; 511 } 512 513 /** 514 * ファイル区切り文字を変換します。 515 * 516 * @param path 変換前文字列 517 * @return 返還後文字列 518 */ 519 protected String replaceFileSeparetor(final String path) { 520 if (StringUtil.isNull(path)) { 521 return ""; 522 } 523 524 return path.replaceAll("\\\\", "/"); 525 } 526 527 /** 528 * フィルター処理を行う 529 * 530 * @param list フィルタを行うリスト 531 * @param filter フィルタ情報 532 * @return フィルタ後のリスト 533 */ 534 protected FileOperation[] filter(List<FileOperationInfo> list, FileOperationFileFilter filter) { 535 ArrayList<FileOperationInfo> files = new ArrayList<FileOperationInfo>(); 536 for (int i = 0; i < list.size(); i++) { 537 if (filter.accept(list.get(i))) { 538 files.add(list.get(i)); 539 } 540 } 541 return files.toArray(new FileOperationInfo[files.size()]); 542 } 543 544 /** 545 * InputStreamをbyte[]に変換。 546 * InputStreamのサイズ計算に利用。 547 * 548 * @param is byte[]変換するInputStream 549 * @return InpusStreamをbyte[]に変換した値 550 */ 551 protected byte[] toByteArray(InputStream is) throws IOException { 552 ByteArrayOutputStream output = new ByteArrayOutputStream(); 553 try { 554 byte[] b = new byte[BUFFER_SIZE]; 555 int n = 0; 556 while ((n = is.read(b)) != -1) { 557 output.write(b, 0, n); 558 } 559 return output.toByteArray(); 560 } finally { 561 output.close(); 562 } 563 } 564} 565