ฉันจะสร้างสตริง Java จากเนื้อหาของไฟล์ได้อย่างไร


1513

ฉันใช้สำนวนข้างล่างมาระยะหนึ่งแล้ว และดูเหมือนจะเป็นเว็บไซต์ที่มีการแพร่กระจายกว้างที่สุดอย่างน้อยก็ในเว็บไซต์ที่ฉันเคยเข้าชม

มีวิธีที่ดีกว่า / แตกต่างในการอ่านไฟล์ในสตริงใน 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();
    }
}

7
ใครช่วยอธิบายฉันด้วยวิธีที่ง่ายมากกับ NIO บ้าง เวลาที่ฉันอ่านเกี่ยวกับ ITI แต่ละได้รับหายไปในการกล่าวถึง n ของช่อง :(
OscarRyz

7
อย่าลืมว่าไม่รับประกันว่าตัวแยกบรรทัดในไฟล์นั้นไม่จำเป็นเหมือนกับตัวแยกบรรทัดของระบบ
Henrik Paul

138
คุณช่วยแทรกการลองที่เหมาะสมในที่สุดซึ่งปิดเครื่องอ่านได้หรือไม่? บางคนอาจใช้ตัวอย่างนี้และแนะนำบั๊กในโค้ดของเขา
Hans-Peter Störr

6
โค้ดด้านบนมีข้อผิดพลาดในการเพิ่มอักขระขึ้นบรรทัดใหม่ที่บรรทัดสุดท้าย ควรเป็นดังนี้ถ้า (line = reader.readLine ())! = null) {stringBuilder.append (บรรทัด); } ในขณะที่ (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (บรรทัด); }
ลึก

27
Java 7 แนะนำbyte[] Files.readAllBytes(file);ผู้ที่แนะนำโซลูชันสแกนเนอร์ 'หนึ่งบรรทัด': คุณไม่จำเป็นต้องปิดหรือไม่
Val

คำตอบ:


1534

อ่านข้อความทั้งหมดจากไฟล์

Java 11 เพิ่มเมธอด readString ()เพื่ออ่านไฟล์ขนาดเล็กเป็น a String, รักษาตัววางสาย:

String content = Files.readString(path, StandardCharsets.US_ASCII);

สำหรับรุ่นระหว่าง Java 7 และ 11 ต่อไปนี้เป็นสำนวนที่กะทัดรัดและทนทานซึ่งรวมอยู่ในวิธีการยูทิลิตี้:

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>แสดงเป็น วิธีนี้คือ "lossy" เนื่องจากตัวแยกบรรทัดถูกแยกออกจากส่วนท้ายของแต่ละบรรทัด

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

Java 8 เพิ่มวิธีการในการผลิตFiles.lines() Stream<String>อีกครั้งวิธีนี้จะสูญเสียเนื่องจากตัวแยกบรรทัดถูกปล้น หากIOExceptionพบว่ามีในขณะที่อ่านไฟล์มันจะถูกห่อในUncheckedIOExceptionเนื่องจากStreamไม่ยอมรับ lambdas ที่โยนข้อยกเว้นที่ตรวจสอบแล้ว

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

นี้Streamไม่จำเป็นต้องclose()โทร; นี่เป็นเอกสารที่ไม่ดีบน API และฉันสงสัยว่าหลายคนไม่ได้สังเกตเห็นว่าStreamมีclose()วิธี ต้องแน่ใจว่าใช้ ARM-block ดังที่แสดง

หากคุณทำงานกับแหล่งข้อมูลอื่นนอกเหนือจากไฟล์คุณสามารถใช้lines()วิธีการBufferedReaderแทน

การใช้งานหน่วยความจำ

วิธีแรกที่เก็บรักษาตัวแบ่งบรรทัดอาจต้องใช้หน่วยความจำชั่วคราวหลายครั้งขนาดของไฟล์เพราะในช่วงเวลาสั้น ๆ เนื้อหาไฟล์ดิบ (อาร์เรย์ไบต์) และตัวถอดรหัส (แต่ละที่เป็น 16 บิตแม้ว่าการเข้ารหัส เป็น 8 บิตในไฟล์) อยู่ในหน่วยความจำพร้อมกัน จะปลอดภัยที่สุดที่จะใช้กับไฟล์ที่คุณรู้ว่ามีขนาดเล็กเมื่อเทียบกับหน่วยความจำที่มีอยู่

วิธีที่สองบรรทัดการอ่านมักจะมีหน่วยความจำมีประสิทธิภาพมากขึ้นเนื่องจากบัฟเฟอร์ไบต์อินพุตสำหรับการถอดรหัสไม่จำเป็นต้องมีไฟล์ทั้งหมด อย่างไรก็ตามยังคงไม่เหมาะสำหรับไฟล์ที่มีขนาดใหญ่มากเมื่อเทียบกับหน่วยความจำที่มีอยู่

สำหรับการอ่านไฟล์ขนาดใหญ่คุณต้องมีการออกแบบที่แตกต่างกันสำหรับโปรแกรมของคุณหนึ่งไฟล์ที่อ่านข้อความจำนวนมากจากสตรีมประมวลผลจากนั้นย้ายไปยังส่วนต่อไปแล้วนำบล็อกหน่วยความจำขนาดคงที่มาใช้ซ้ำ ที่นี่ "ใหญ่" ขึ้นอยู่กับรายละเอียดของคอมพิวเตอร์ ทุกวันนี้เกณฑ์นี้อาจมี RAM หลายกิกะไบต์ วิธีที่สามการใช้ a Stream<String>เป็นวิธีหนึ่งในการทำเช่นนี้หากอินพุต "บันทึก" ของคุณเกิดขึ้นเป็นแต่ละบรรทัด (การใช้readLine()วิธีการBufferedReaderเป็นขั้นตอนที่เทียบเท่ากับวิธีการนี้)

การเข้ารหัสอักขระ

สิ่งหนึ่งที่ขาดหายไปจากตัวอย่างในโพสต์ต้นฉบับคือการเข้ารหัสอักขระ มีกรณีพิเศษบางอย่างที่ค่าเริ่มต้นของแพลตฟอร์มเป็นสิ่งที่คุณต้องการ แต่เป็นกรณีที่หายากและคุณควรจะสามารถพิสูจน์ตัวเลือกของคุณได้

StandardCharsetsระดับกำหนดค่าคงที่บางอย่างสำหรับการเข้ารหัสที่จำเป็นทั้งหมด runtimes Java:

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

เริ่มต้นแพลตฟอร์มสามารถใช้ได้จากระดับตัวเอง:Charset

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

หมายเหตุ: คำตอบนี้ส่วนใหญ่จะแทนที่รุ่น Java 6 ของฉัน ยูทิลิตี้ของ Java 7 ทำให้รหัสง่ายขึ้นอย่างปลอดภัยและคำตอบเก่าซึ่งใช้บัฟเฟอร์ไบต์ที่แมปป้องกันไฟล์ที่ถูกอ่านจากการถูกลบจนกว่าบัฟเฟอร์ที่แมปจะถูกเก็บรวบรวมขยะ คุณสามารถดูเวอร์ชั่นเก่าผ่านลิงค์ "แก้ไข" ในคำตอบนี้


3
เทคนิคการพูดมันเป็น O (n) ในเวลาและสถานที่ ในเชิงคุณภาพเนื่องจากความต้องการที่ไม่สามารถเปลี่ยนแปลงได้ของ Strings มันค่อนข้างยากในหน่วยความจำ ชั่วคราวมีข้อมูลถ่านสองชุดในหน่วยความจำรวมทั้งห้องสำหรับไบต์ที่เข้ารหัส สมมติว่าการเข้ารหัสไบต์เดียวบางอย่างมันจะ (ชั่วคราว) ต้องการหน่วยความจำ 5 ไบต์สำหรับอักขระแต่ละตัวในไฟล์ เนื่องจากคำถามนั้นถามถึง String โดยเฉพาะนั่นคือสิ่งที่ฉันแสดง แต่ถ้าคุณสามารถทำงานกับ CharBuffer ที่ส่งกลับโดย "ถอดรหัส" ความต้องการหน่วยความจำก็น้อยกว่ามาก เวลาที่เหมาะสมฉันไม่คิดว่าคุณจะพบอะไรที่เร็วกว่าใน libs core Java
erickson

5
พิมพ์ผิดที่เป็นไปได้? NIO มีคลาส Charset (ไม่ใช่ CharSet) ชื่อ java.nio.charset.Charset สิ่งนี้เป็นสิ่งที่ CharSet ควรได้รับ?
Jonathan Wright

31
หมายเหตุ: หลังจากออกกำลังกายรหัสนั้นเล็กน้อยฉันพบว่าคุณไม่สามารถลบไฟล์ได้อย่างน่าเชื่อถือหลังจากอ่านด้วยวิธีนี้ซึ่งอาจเป็นปัญหาในบางกรณี แต่ไม่ใช่ของฉัน อาจเกี่ยวข้องกับปัญหานี้หรือไม่: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ในที่สุดฉันก็ไปตามข้อเสนอของ Jon Skeet ที่ไม่ได้รับจากข้อผิดพลาดนี้ ยังไงก็ตามฉันแค่อยากจะให้ข้อมูลสำหรับคนอื่น ๆ ในกรณี ...
Sébastien Nussbaumer

5
@ Sébastien Nussbaumer: ฉันก็เจอปัญหานี้เช่นกัน น่าทึ่งที่ข้อผิดพลาดนั้นถูกทำเครื่องหมายว่า "จะไม่แก้ไข" สิ่งนี้หมายความว่าFileChannel#mapโดยทั่วไปไม่สามารถใช้งานได้
Joonas Pulakka

4
@ Sébastien Nussbaumer: ข้อผิดพลาดถูกลบออกจากฐานข้อมูล Oracle / Sun Bug: "ข้อผิดพลาดนี้ไม่พร้อมใช้งาน" Google แคชเว็บไซต์ที่webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
bobndrew

351

หากคุณยินดีที่จะใช้ห้องสมุดภายนอกให้ตรวจสอบApache Commons IO (200KB JAR) มันมีorg.apache.commons.io.FileUtils.readFileToString()วิธีการที่ช่วยให้คุณสามารถอ่านทั้งหมดFileลงในStringด้วยรหัสหนึ่งบรรทัด

ตัวอย่าง:

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

ฉันไม่พบวิธีดังกล่าวใน URL ที่คุณระบุ
OscarRyz

2
มันอยู่ในชั้นเรียน org.apache.commons.io.FileUtils
Cyrille Ka

2
ฉันใช้ FileUtils ด้วย แต่ฉันสงสัยว่ามีอะไรดีกว่าระหว่างการใช้ FileUtils หรือคำตอบ nio ที่ยอมรับ?
Guillaume

4
@Gillaillaume: คำถามที่ใหญ่ที่สุดคือคุณพอใจที่จะพึ่งพาห้องสมุดบุคคลที่สามหรือไม่ หากคุณมี Commons IO หรือGuavaในโครงการของคุณให้ใช้สิ่งนั้น (เพื่อความเรียบง่ายของโค้ดไม่เช่นนั้นจะไม่มีความแตกต่างที่เห็นได้ชัด)
Jonik

183

วิธีการแก้ปัญหาแบบลีนมากขึ้นอยู่กับ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

หรือด้วยการลองกับทรัพยากรบล็อกซึ่งจะโทร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


4
\\ A ใช้งานได้เนื่องจากไม่มี "จุดเริ่มต้นของไฟล์อื่น" ดังนั้นคุณจึงอ่านโทเค็นสุดท้าย ... ซึ่งเป็นอันแรกด้วย ไม่เคยลองด้วย \\ Z นอกจากนี้โปรดทราบว่าคุณสามารถอ่านสิ่งที่อ่านได้เช่นไฟล์, InputStreams, ช่อง ... บางครั้งฉันใช้รหัสนี้เพื่ออ่านจากหน้าต่างแสดงผลของ eclipse เมื่อฉันไม่แน่ใจว่าฉันกำลังอ่านไฟล์หนึ่งหรืออีก .. . ใช่ classpath ทำให้ฉันสับสน
Pablo Grisafi

1
ในฐานะผู้โพสต์ฉันสามารถบอกได้ว่าจริงๆแล้วฉันไม่รู้ว่าไฟล์นั้นถูกต้องหรือไม่ ... ฉันไม่เคยเขียนรหัสนี้ในรหัสการผลิตฉันใช้มันเพื่อการทดสอบหรือการดีบักเท่านั้น
Pablo Grisafi

2
มีขีด จำกัด 1024 ตัวอักษรฉันคิดว่า
Whimusical

20
เครื่องสแกนใช้งาน Closeable (จะเรียกใช้ปิดแหล่งที่มา) - ดังนั้นในขณะที่สง่างามมันไม่ควรจะเป็นหนึ่งซับ ขนาดเริ่มต้นของบัฟเฟอร์คือ 1024 แต่สแกนเนอร์จะเพิ่มขนาดตามความจำเป็น (ดูที่เครื่องสแกน # makeSpace ())
earcam

8
java.util.NoSuchElementExceptionหนึ่งนี้ล้มเหลวสำหรับไฟล์ที่ว่างเปล่าด้วย
SpaceTrucker

116
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

ตั้งแต่ java 7 คุณสามารถทำได้ด้วยวิธีนี้


สิ่งนี้ควรได้รับการยอมรับว่าเป็นคำตอบ - บรรทัดเดียวไม่มี libs ภายนอก
Cherry

สิ่งนี้เพิ่มอักขระขึ้นบรรทัดใหม่ในตอนท้ายแม้ว่าจะไม่ปรากฏในไฟล์
Stefan Haberl

79

หากคุณกำลังมองหาทางเลือกที่ไม่เกี่ยวข้องกับห้องสมุดบุคคลที่สาม (เช่นคอมมอนส์ I / O ) คุณสามารถใช้คลาสสแกนเนอร์ :

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

2
ฉันคิดว่านี่เป็นวิธีที่ดีที่สุด ตรวจสอบjava.sun.com/docs/books/tutorial/essential/io/scanning.html
Tarski

3
ตัวสร้างสแกนเนอร์ที่ยอมรับสตริงจะไม่ถือว่าสตริงเป็นชื่อไฟล์ที่จะอ่าน แต่เป็นข้อความที่จะสแกน ฉันทำผิดพลาดตลอดเวลา : - /
Alan Moore

@ อลันจับได้ดี ฉันแก้ไขคำตอบของดอนเล็กน้อยเพื่อแก้ไข (ฉันหวังว่า)
Jonik

3
fileContents.append (scanner.nextLine ()) ผนวก (lineSeparator).
บ้าน geoengineering

1
Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));เปลี่ยนแปลงคำสั่งเริ่มต้นที่จะ มิฉะนั้นคุณสามารถจับภาพบางส่วนของไฟล์เท่านั้น
Wei Yang

71

ฝรั่งมีวิธีการคล้ายกับวิธีหนึ่งจาก Commons IOUtils ที่ Willi aus Rohr พูดถึง:

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

// ...

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

แก้ไขโดย PiggyPiglet
Files#toStringเลิกใช้แล้วและครบกำหนดให้นำออก Octobor 2019 แทนที่จะใช้ Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

แก้ไขโดย Oscar Reyes

นี่คือรหัสพื้นฐาน (ประยุกต์) บนไลบรารีที่อ้างถึง:

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 ล่าสุด สำหรับแหล่งปัจจุบันดูคลาสFiles , CharStreams , ByteSourceและCharSourceในแพ็คเกจcom.google.common.io


รหัสนี้มีแคสต์จากยาวถึง int ซึ่งอาจปรากฏพฤติกรรมที่บ้าคลั่งกับไฟล์ขนาดใหญ่ มีช่องว่างเพิ่มเติมและคุณปิดอินสตรีมที่ใด
Mohamed Taher Alrefaie

@MTA: กระแสถูกปิดทราบใช้CloserในCharSource รหัสในคำตอบนั้นไม่ใช่แหล่งฝรั่งจริง
Jonik

54
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 "";
    }

6
หรือง่ายยิ่งขึ้น:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));

12
หรือnew String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo

1
เล่นได้ดีและจะบันทึกผู้ชายถัดไป Googling, Pathsเห็นได้ชัดคือ 1.7+FileSystemsตามที่เป็นอยู่ (Dang it!)
ruffin

4
มันน่าละอายที่คำตอบนี้ไม่มีการลงคะแนนมากกว่านี้ ฉันกำลังมองหาวิธีที่รวดเร็วและง่ายที่สุดในการรับไฟล์ข้อความลงในสตริง นี่คือและถ้าฉันไม่ได้เลื่อนลงและลงฉันจะพลาด OP ควรพิจารณายอมรับคำตอบนี้เพื่อย้ายไปด้านบน
หนาม

@Thorn คำตอบนี้มีการจัดการข้อผิดพลาดที่น่ากลัว อย่าใช้วิธีนี้ในรหัสการผลิตหรือดีกว่า: ไม่
xehpuk

51

หากคุณต้องการการประมวลผลสตริง (การประมวลผลแบบขนาน) Java 8 มี 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

อีกตัวอย่างหนึ่งซับ

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

. Parallel () เกิดขึ้นหลังจากที่คุณอ่านบรรทัดหรือก่อนหน้านั้นหรือไม่
Istvan

การทำงานจริงเริ่มต้นขึ้นเนื่องจากการรวบรวมการทำงานของเทอร์มินัล (... ) ถูกเรียกใช้ สตรีมนั้นมีการเติมข้อมูลทีละบรรทัดอย่างเกียจคร้าน ไม่จำเป็นต้องอ่านไฟล์ทั้งหมดในหน่วยความจำก่อนประมวลผล (เช่นการกรองและการแมป)
Andrei N

ตัดก่อนเลือกบรรทัดที่ไม่ว่างเปล่า?
Thorbjørn Ravn Andersen

50

รหัสนั้นจะทำให้การแบ่งบรรทัดเป็นปกติซึ่งอาจเป็นหรือไม่ใช่สิ่งที่คุณต้องการจะทำ

นี่คือทางเลือกที่ไม่ทำเช่นนั้นและเป็น (IMO) ที่เข้าใจง่ายกว่ารหัส NIO (แม้ว่าจะยังคงใช้อยู่java.nio.charset.Charset):

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

1
ยกโทษให้ฉันสำหรับการฟื้นฟูความคิดเห็นเก่านี้ แต่คุณหมายถึงการส่งผ่านวัตถุ String ที่เรียกว่า "file" หรือควรเป็นวัตถุ File แทนหรือไม่
ไบรอัน Larson

28

รวบรวมวิธีที่เป็นไปได้ทั้งหมดเพื่ออ่านไฟล์เป็นสตริงจากดิสก์หรือเครือข่าย

  • ฝรั่ง: Googleใช้คลาสResources,Files

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

  • APACHE - COMMONS IOโดยใช้คลาส IOUtils, FileUtils

    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โดยใช้Stream 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()));
    }

  • เครื่องสแกนเนอร์ชั้นกับ \Aregex ซึ่งตรงกับจุดเริ่มต้นของอินพุต

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

  • BufferedReaderInputStreamReaderการใช้

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

ตัวอย่างด้วยวิธีการหลักในการเข้าถึงวิธีการดังกล่าว

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

@ดู


26

หากเป็นไฟล์ข้อความทำไมไม่ใช้apache คอมมอนส์ -io ?

มันมีวิธีการดังต่อไปนี้

public static String readFileToString(File file) throws IOException

หากคุณต้องการให้บรรทัดเป็นรายการใช้

public static List<String> readLines(File file) throws IOException

25

ตั้งแต่ 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

ทำไมโอ๋ทำไมจึงแนะนำวิธีการใหม่ที่ต้องพึ่งพาชุดอักขระเริ่มต้นในปี 2018
mryan

2
@ mryan วิธีนี้ไม่ได้พึ่งพาชุดอักขระเริ่มต้นของระบบ เป็นค่าเริ่มต้นเป็น UTF-8 ซึ่งใช้ได้
leventov

@ leventov คุณพูดถูก! Files.readAllLines ก็เช่นกัน! ที่ทำให้ API ไฟล์นั้นไม่สอดคล้องกับวิธีเก่ากว่า แต่จะดีกว่า :)
mryan

17

หากต้องการอ่านไฟล์เป็นไบนารีและแปลงที่ส่วนท้าย

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

ด้วย Java 7 นี่เป็นตัวเลือกที่ฉันต้องการอ่านไฟล์ UTF-8:

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

ตั้งแต่ Java 7, JDK มีjava.nio.fileAPI ใหม่ซึ่งมีทางลัดมากมายดังนั้นไลบรารีของบุคคลที่สามจึงไม่จำเป็นต้องใช้สำหรับการดำเนินงานไฟล์อย่างง่ายเสมอไป


15

Java พยายามที่จะเป็นคนทั่วไปและมีความยืดหยุ่นในทุกสิ่งที่มันทำ ดังนั้นสิ่งที่ค่อนข้างง่ายในภาษาสคริปต์ (รหัสของคุณจะถูกแทนที่ด้วย " open(file).read()" ในงูใหญ่) มีความซับซ้อนมากขึ้น ดูเหมือนจะไม่มีวิธีที่สั้นกว่าในการทำยกเว้นใช้ห้องสมุดภายนอก (เช่นWilli aus Rohr ที่กล่าวถึง) ทางเลือกของคุณ:

  • ใช้ไลบรารีภายนอก
  • คัดลอกรหัสนี้ไปยังโครงการทั้งหมดของคุณ
  • สร้างห้องสมุดขนาดเล็กของคุณเองซึ่งมีฟังก์ชั่นที่คุณใช้บ่อย

ทางออกที่ดีที่สุดของคุณน่าจะเป็นอันดับ 2 เนื่องจากมีการอ้างอิงน้อยที่สุด


4
Yeap มันทำให้ภาษาระดับ "สูง" มีความหมายแตกต่างกัน Java อยู่ในระดับสูงเมื่อเทียบกับ C แต่ต่ำเมื่อเทียบกับ Python หรือ Ruby
OscarRyz

3
ยอมรับว่า Java มีความยาวใน abstractions ระดับสูง แต่ย่อมาจากวิธีการอำนวยความสะดวก
Dónal

3
True, Java มีวิธีการจัดการกับไฟล์จำนวนน้อยและหลายคนดูเหมือนจะซับซ้อน แต่นี่ค่อนข้างใกล้เคียงกับสิ่งที่เรามีในภาษาระดับสูงกว่านี้:byte[] bytes = Files.readAllBytes(someFile.toPath());
หนาม

11

ใช้ JDK 8 หรือสูงกว่า:

ไม่ใช้ไลบรารีภายนอก

คุณสามารถสร้างวัตถุ String ใหม่จากเนื้อหาไฟล์ (การใช้คลาสจากjava.nio.fileแพ็คเกจ):

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

คำตอบซ้ำของ Moritz Petersen ผู้เขียน: เนื้อหา String = สตริงใหม่ (Files.readAllBytes (Paths.get (ชื่อไฟล์)), "UTF-8");
Jean-Christophe Blanchard

8

มีการเปลี่ยนแปลงในชุดรูปแบบเดียวกันกับที่ใช้สำหรับวนรอบแทนห่วงสักครู่เพื่อ จำกัด ขอบเขตของตัวแปรบรรทัด ไม่ว่าจะเป็น "ดีกว่า" เป็นเรื่องของรสนิยมส่วนตัว

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

3
สิ่งนี้จะเปลี่ยนการขึ้นบรรทัดใหม่เป็นการเลือกขึ้นบรรทัดใหม่ สิ่งนี้อาจเป็นที่ต้องการหรือไม่ตั้งใจ
Peter Lawrey

ย้อนกลับการแก้ไขคำตอบนี้เพราะประเด็นคือเพื่อ จำกัด ขอบเขตของlineตัวแปร การแก้ไขประกาศมันสองครั้งซึ่งจะเป็นข้อผิดพลาดในการคอมไพล์
Dan Dyer

7

หากคุณไม่มีสิทธิ์เข้าถึง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);
}

ชุดอักขระตัวอย่างที่จะเรียกใช้?
Thufir

4

โซลูชันที่ยืดหยุ่นโดยใช้IOUtilsจาก Apache Commons-ioร่วมกับStringWriter :

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

มันทำงานร่วมกับผู้อ่านหรือสตรีมอินพุตใด ๆ (ไม่ใช่แค่กับไฟล์) เช่นเมื่ออ่านจาก URL


3

โปรดระวังเมื่อใช้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();
}

ควรพิจารณาว่าวิธีนี้ไม่เหมาะสำหรับการเข้ารหัสอักขระแบบหลายไบต์เช่น UTF-8


1
รหัสนี้อาจให้ผลลัพธ์ที่คาดเดาไม่ได้ ตามเอกสารของavailable()วิธีการนั้นไม่มีการรับประกันว่าจะถึงจุดสิ้นสุดของไฟล์ในกรณีที่เมธอดส่งคืนค่า 0 ในกรณีนี้คุณอาจจบด้วยไฟล์ที่ไม่สมบูรณ์ ยิ่งไปกว่านั้นจำนวนไบต์ที่อ่านจริงอาจน้อยกว่าค่าที่ส่งคืนโดยavailable()ในกรณีนี้คุณจะได้รับผลลัพธ์ที่เสียหาย
ล่ะ

3

อันนี้ใช้วิธี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

คุณสามารถลองคลาสสแกนเนอร์และไฟล์ซึ่งเป็นโซลูชันสองสามบรรทัด

 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

ผู้ใช้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
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();
}

ฉันคิดว่านี่เป็นระบบปฏิบัติการที่ไม่สะดวกโดยใช้การเข้ารหัสเริ่มต้นของแพลตฟอร์ม +1 ต่อไป :)
OscarRyz

7
ฉันดูเหมือนว่าในที่สุดบล็อกไม่ทราบว่าตัวแปรที่กำหนดไว้ในบล็อกลอง javac 1.6.0_21 cannot find symbolโยนข้อผิดพลาด
ceving

คุณลองใช้รหัสของคุณเองหรือยัง คุณได้กำหนดผู้อ่านในบล็อก try / catch ดังนั้นจึงไม่สามารถเข้าถึงได้ในที่สุดบล็อก
mauron85

2

ฉันยังไม่สามารถคอมเมนต์รายการอื่นได้ดังนั้นฉันจะทิ้งไว้ที่นี่

หนึ่งในคำตอบที่ดีที่สุดที่นี่ ( 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();
}
}

ยังคงมีข้อบกพร่องหนึ่ง มันมักจะใส่อักขระขึ้นบรรทัดใหม่ในตอนท้ายของสตริงซึ่งอาจทำให้เกิดข้อผิดพลาดบางอย่าง คำแนะนำของฉันคือเปลี่ยนเป็น:

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

ในกรณีแรกคุณอาจเพิ่มบรรทัดใหม่พิเศษในตอนท้าย ในกรณีที่สองคุณอาจจะละไว้ ดังนั้นทั้งคู่จึงผิดอย่างเท่าเทียมกัน ดูบทความนี้
แพทริคปาร์กเกอร์

2

หลังจาก Ctrl + F'ing หลังจากสแกนเนอร์ฉันคิดว่าควรจะแสดงโซลูชันของสแกนเนอร์ด้วย ในการอ่านแฟชั่นที่ง่ายที่สุดมันจะเป็นดังนี้:

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 หรือใหม่กว่า (และคุณควรจริง ๆ ) ลองใช้การลองกับแหล่งข้อมูลเพื่อให้อ่านง่ายขึ้น ไม่มีสิ่งที่จุดปิดเกลื่อนทุกอย่าง แต่นั่นเป็นตัวเลือกที่เป็นตัวเลือกสำนวนโวหาร

ฉันโพสต์สิ่งนี้เป็นส่วนใหญ่เพื่อความสมบูรณ์เพราะถ้าคุณต้องทำสิ่งนี้มาก ๆ ควรมีสิ่งต่าง ๆ ในjava.nio.file.Filesที่ควรทำงานให้ดีขึ้น

ข้อเสนอแนะของฉันจะใช้Files # readAllBytes (Path)เพื่อคว้าไบต์ทั้งหมดและป้อนไปยังStringใหม่(byte [] Charset)เพื่อดึงสตริงออกมาจากที่คุณเชื่อถือได้ ชุดอักขระจะมีความหมายกับคุณในช่วงชีวิตของคุณดังนั้นระวังสิ่งนี้ทันที

คนอื่นให้รหัสและสิ่งของและฉันไม่ต้องการขโมยชื่อเสียงของพวกเขา ;)



2

นอกจากนี้หากไฟล์ของคุณอยู่ในขวดคุณสามารถใช้สิ่งนี้:

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

จากคำตอบของ @ 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()]));
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.