web-dev-qa-db-ja.com

ファイルの内容からJava文字列を作成する方法

私は今しばらくの間下のイディオムを使っています。そしてそれは、少なくとも私が訪れたサイトでは、最も広まっているようです。

Javaでファイルを文字列に読み込むためのより良い/異なる方法はありますか?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}
1365
OscarRyz

ファイルからすべてのテキストを読む

これは、ユーティリティメソッドにまとめられた、Java 7のコンパクトで堅牢な慣用句です。

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

ファイルからテキスト行を読み込む

Java 7では、ファイルをテキスト行として読み取るための 便利なメソッドが追加されました。List<String>として表されます。行区切り文字が各行の末尾から削除されるので、このアプローチは「損失」です。

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

Java 8ではStream<String>を生成するために Files.lines() メソッドが追加されました。繰り返しになりますが、この方法は行区切り文字が取り除かれるため損失があります。ファイルの読み込み中にIOExceptionが見つかった場合、UncheckedIOExceptionはチェック例外をスローするラムダを受け付けないため、 Stream にラップされます。

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

このStreamclose() 呼び出しを必要としません。これはAPIについてはあまり文書化されていません。そしてStreamclose()メソッドを持っていることに気づいていない人も多くいると思います。図のように必ずARMブロックを使用してください。

ファイル以外のソースで作業している場合は、代わりにBufferedReaderlines() メソッドを使用できます。

メモリ使用率

最初の方法では、改行を保存しますが、一時的にファイルサイズの数倍のメモリ容量が必要になることがあります。これは、しばらくの間、生ファイルの内容(バイト配列)とデコード文字ファイル内の8ビット)が一度にメモリに常駐します。利用可能なメモリに比べて小さいことがわかっているファイルに適用するのが最も安全です。

2番目の方法である行の読み取りは、通常、デコードのための入力バイトバッファにファイル全体を含める必要がないため、メモリ効率が高くなります。ただし、利用可能なメモリに対して非常に大きいファイルにはまだ適していません。

大きなファイルを読み込むためには、プログラムから別のデザインが必要です。ストリームからテキストのチャンクを読み込み、それを処理し、次に同じ固定サイズのメモリブロックを再利用するというものです。ここで、「大」とはコンピュータの仕様によって異なります。今日、このしきい値は何ギガバイトのRAMかもしれません。あなたの入力 "records"が偶然個々の行であるならば、Stream<String>を使用する3番目の方法はこれをする1つの方法です。 (BufferedReaderreadLine()メソッドを使用することは、このアプローチと同等の手続きです。)

文字コード

元の記事のサンプルから欠けていることの1つは、文字エンコードです。プラットフォームのデフォルトがあなたが望むものであるという特別な場合がいくつかありますが、それらはまれであり、あなたはあなたの選択を正当化できるはずです。

StandardCharsets クラスは、すべてのJavaランタイムに必要なエンコーディングのためのいくつかの定数を定義します。

String content = readFile("test.txt", StandardCharsets.UTF_8);

プラットフォームのデフォルトは Charsetクラス から入手できます。

String content = readFile("test.txt", Charset.defaultCharset());

注:この回答は、私のJava 6バージョンの大部分を置き換えます。 Java 7のユーティリティは安全にコードを単純化し、マップされたバイトバッファを使用していた古い答えは、マップされたバッファがガベージコレクションされるまで削除されるのを防ぎました。あなたはこの答えの「編集された」リンクを通して古いバージョンを見ることができます。

1388
erickson

外部ライブラリを使用したい場合は、 Apache Commons IO (200KB JAR)を調べてください。 1行のコードでFile全体をStringに読み込むことができる org.Apache.commons.io.FileUtils.readFileToString() メソッドが含まれています。

例:

import Java.io.*;
import Java.nio.charset.*;
import org.Apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}
316
Willi aus Rohr

Scanner に基づく非常に無駄のないソリューション

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

あるいは、文字セットを設定したい場合は、

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

または、 try-with-resources ブロックを使用すると、scanner.close()が呼び出されます。

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

ScannerコンストラクタはIOExceptionをスローできることを忘れないでください。そしてJava.ioJava.utilをインポートすることを忘れないでください。

ソース: Pat Niemeyerのブログ

172
Pablo Grisafi
import Java.nio.file.Files;
import Java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");

java 7以降では、このようにすることができます。

92
Jobin Joseph

もしあなたがサードパーティのライブラリを含まない代替を探しているなら(例えば Commons I/O )、 Scanner クラスを使うことができます:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}
75
Dónal

Guava には、Willi aus Rohrが述べたCommons IOUtilsのものと似た方法があります。

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

オスカーレイエスによる編集

これは、引用されているライブラリの(単純化された)基本コードです。

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

編集 (Jonik作):上記はGuavaの最近のバージョンのソースコードと一致しません。現在のソースについては、 com.google.common.io パッケージの FilesCharStreamsByteSource 、および CharSource の各クラスを参照してください。

67
finnw
import Java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }
51
user590444

そのコードは改行を正規化します。それはあなたが本当にやりたいことかもしれません。

これをしない、そして(Java.nio.charset.Charsetを使用していますが)NIOコードより(IMO)理解しやすい代替方法があります。

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}
49
Jon Skeet

文字列処理(並列処理)が必要な場合は、Java 8に素晴らしいStream APIがあります。

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

JDKサンプルsample/lambda/BulkDataOperationsには、 Oracle Java SE 8ダウンロードページ からダウンロードできるその他の例があります。

もう1つのライナーの例

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
47
Andrei N

ファイルをディスクまたはネットワークから文字列として読み取るために考えられるすべての方法をまとめました。

  • Guava:Google クラスを使用する ResourcesFiles

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }
    

  • クラスIOUtils、FileUtilsを使用して Apache - COMMONS IO

    static Charset encoding = org.Apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        Java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }
    

  • Java 8 BufferReader using ストリームAPI

    public static String streamURL_Buffer( URL url ) throws IOException {
        Java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }
    

  • 正規表現\Aを持つスキャナークラス。これは入力の先頭に一致します。

    static String charsetName = Java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        Java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    

  • Java 7(Java.nio.file.Files.readAllBytes

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = Java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }
    

  • BufferedReaderを使用してInputStreamReader

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }
    

上記のメソッドにアクセスするためのmainメソッドの例.

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@見る

25
Yash

テキストファイルの場合は、 Apache commons-io を使用しないでください。

以下の方法があります

public static String readFileToString(File file) throws IOException

リストとして行を使用したい場合

public static List<String> readLines(File file) throws IOException
24
Home in Time

JDK 11以降:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8
22
leventov

ファイルをバイナリとして読み取り、最後に変換するには

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}
16
Peter Lawrey

Java 7では、これはUTF-8ファイルを読むための私の望ましい選択です:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

Java 7以降、JDKには多くのショートカットを提供する新しいJava.nio.file APIがあります。そのため、単純なファイル操作にサードパーティのライブラリが必ずしも必要とは限りません。

16
Moritz Petersen

Javaは非常に一般的で柔軟性のあるものにしようとしています。結果として、スクリプト言語で比較的単純なもの(あなたのコードはpythonでは "open(file).read()"に置き換えられるでしょう)はもっとずっと複雑です。 ( Willi aus Rohr のように)外部ライブラリを使用する以外は、これを行うためのより短い方法はないようです。あなたのオプション:

  • 外部ライブラリを使用してください。
  • このコードをすべてのプロジェクトにコピーしてください。
  • 頻繁に使用する機能を含む独自のミニライブラリを作成します。

あなたの最善の策はおそらくそれが最小の依存関係を持っているので、2番目のものです。

15
Claudiu

JDK 8以上を使用している場合

外部ライブラリを使用しない

ファイルの内容から新しいStringオブジェクトを作成することができます(Java.nio.fileパッケージのクラスを使用)。

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}
11
Saikat

Line変数の範囲を制限するために、whileループの代わりにforループを使用するという同じテーマのバリエーションがあります。それが「より良い」かどうかは個人的な好みの問題です。

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}
8
Dan Dyer

Filesクラスにアクセスできない場合は、ネイティブソリューションを使用できます。

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}
7
Ilya Gazman

IOUtils をApacheの commons-ioStringWriter と組み合わせて使用​​する柔軟なソリューション。

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

たとえばURLから読み取る場合など、任意のリーダーまたは入力ストリーム(ファイルだけでなく)でも機能します。

4
wau
public static String Slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}
3
Scott S. McCoy

fileInputStream.available()を使用する場合、返される整数は実際のファイルサイズを表す必要はありませんが、IOをブロックすることなくシステムがストリームから読み取ることができる推定バイト数を表す必要があります。安全で簡単な方法は次のようになります

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

このアプローチはnotはUTF-8のようなマルチバイト文字エンコーディングに適していると考えるべきです。

3
Henry

ScannerとFileクラス、数行のソリューションを試すことができます

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}
3
jamesjara

ファイルのすべての行を読み取るためのユーザーJava.nio.Files

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}
3
Nitin Vavdiya

これはメソッドRandomAccessFile.readFullyを使用します、それはJDK 1.0から利用可能であるようです!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}
3
barjak

一行で(Java 8)、読者がいると仮定します。

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
2

このライブラリ を使用すると、1行になります。

String data = IO.from(new File("data.txt")).toString();
2
satnam

@ ericksonの回答に基づいて、次のものを使用できます。

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
2
Muskovets

Scannerの後でCtrl + Fを押すと、Scannerソリューションも表示されるはずです。最も読みやすいファッションでは、このようになります。

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

Java 7以降を使用している(そして実際にすべきである)場合は、コードを読みやすくするためにtry-with-resourcesを使用することを検討してください。ドットを閉じたものがすべてを捨てることはもうありません。しかし、それは主に文体的な選択です。

私はこれをほとんど完了主義のために投稿しています、なぜならこれをたくさんする必要があるならば、 Java.nio.file.Files には仕事をより良くするはずのものがあるはずです。

私の提案は、 Files#readAllBytes(Path) を使用してすべてのバイトを取得し、それを新しい String(byte [] Charset) に渡して信頼できる文字列を取得することです。あなたの一生の間、文字セットはあなたにとって意味のあるものになるでしょうから、今このことに注意してください。

他の人たちがコードとものを与えてくれました、そして私は彼らの栄光を盗みたくはありません。 ;)

2
Haakon Løtveit

もしあなたのファイルがたまたまjarの中にあるのなら、これも使うことができます。

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

あなたのjarファイルが例えばの場合、パスは/で始まっているはずです。

my.jar/com/some/thing/a.txt

それからあなたはこのようにそれを呼び出したいです:

String myTxt = fromFileInJar("/com/com/thing/a.txt");
2
OscarRyz

他のエントリーはまだコメントできませんので、ここに残しておきます。

ここで最良の答えの1つ( https://stackoverflow.com/a/326448/1521167 ):

private String readFile(String pathname) throws IOException {

File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");

try {
    while(scanner.hasNextLine()) {        
        fileContents.append(scanner.nextLine() + lineSeparator);
    }
    return fileContents.toString();
} finally {
    scanner.close();
}
}

まだ1つ欠陥があります。常に新しい行charを文字列の末尾に入れます。これは奇妙なバグを引き起こすかもしれません。私の提案はそれを次のように変更することです。

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}
1
Ajk

コードを使用:

File file = new File("input.txt");
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
                file));
byte[] buffer = new byte[(int) file.length()];
bin.read(buffer);
String fileStr = new String(buffer);

fileStrの出力はStringです。

0
Devram Kandhare