file شرح - كيف أقوم بإنشاء سلسلة Java من محتويات الملف؟




الكونستركتر في (25)

لقد تم استخدام المصطلح أدناه لبعض الوقت الآن. ويبدو أنها الأكثر انتشارًا ، على الأقل على المواقع التي زرتها.

هل هناك طريقة أفضل / مختلفة لقراءة ملف إلى سلسلة في جاوة؟

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

Answers

العموم FileUtils.readFileToString :

public static String readFileToString(File file)
                       throws IOException

يقرأ محتويات ملف إلى سلسلة باستخدام الترميز الافتراضي لـ VM. الملف مغلق دائما.

المعلمات:

  • file - يجب أن يكون الملف للقراءة ، لا شيء

عائدات: محتويات الملف ، لا شيء باطل

يلقي: - IOException - في حالة وجود خطأ I / O

منذ ذلك الحين: Commons IO 1.3.1

الشفرة المستخدمة (بشكل غير مباشر) بواسطة هذه الفئة هي:

IOUtils.java تحت رخصة أباتشي 2.0 .

public static long copyLarge(InputStream input, OutputStream output)
       throws IOException {
   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
   long count = 0;
   int n = 0;
   while (-1 != (n = input.read(buffer))) {
       output.write(buffer, 0, n);
       count += n;
   }
   return count;
}

إنها مشابهة جدا لتلك المستخدمة من قبل Ritche_W.


إذا كان ملف نصي لماذا لا يستخدم apache commons-io ؟

لديها الطريقة التالية

public static String readFileToString(File file) throws IOException

إذا كنت تريد استخدام الخطوط كقائمة

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

يمكنك محاولة فاحص "الماسح الضوئي والملفات" ، وهو حل قليل الأسطر

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

باستخدام هذه المكتبة ، هو سطر واحد:

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

من هذه الصفحة حل خفيف للغاية:

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

إذا كنت ترغب في ضبط charset


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

استنادًا إلى إجابة erickson ، يمكنك استخدام:

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

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;
/**
 * A simple example program that reads a text file into a String using Files.lines and stream.
 */
public class ReadTextFileExample {
    public static void main(String[] args) throws IOException {
        String contents = Files.lines(Paths.get("c:\\temp\\testfile.txt")).collect(Collectors.joining("\n"));
        System.out.println(contents);
    }
}

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

منذ جافا 7 يمكنك القيام بذلك بهذه الطريقة.


كن على دراية عند استخدام 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.


في جافا 8 ، هناك فئة جديدة

java.util.stream.Stream

يمثل الدفق سلسلة من العناصر ويدعم أنواعًا مختلفة من العمليات لإجراء عمليات حسابية على تلك العناصر

لقراءة المزيد حول هذا الموضوع:

أوراكل الوثائق

هنا مثال:

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public Class ReadFile{
  public  static String readFile(String filePath) {
 StringBuilder  stringBuilder = new StringBuilder();
    String ls = System.getProperty("line.separator");
        try {

            try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
                for (String line : (Iterable<String>) lines::iterator) {


                      stringBuilder.append(line);
                      stringBuilder.append(ls);


                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

      return stringBuilder.toString(); 


}

}

استخدام الكود:

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 يحتوي على الإخراج في سلسلة.


إذا كنت تحتاج إلى معالجة سلسلة (معالجة متوازية) فإن 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

مثال آخر على الخطوط الملاحية المنتظمة

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

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

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

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

لقراءة ملف باسم ثنائي وتحويل في النهاية

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

قراءة كل النص من ملف

في ما يلي صيغة مضغوطة وقوية لـ 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> . هذا الأسلوب "lossy" لأن يتم فصل فواصل الأسطر من نهاية كل سطر.

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

في Java 8 ، أضاف BufferedReader طريقة جديدة ، lines() لإنشاء Stream<String> . إذا تمت مصادفة IOException أثناء قراءة الملف ، فإنه يتم تغليفه في UncheckedIOException ، لأن Stream لا يقبل lambdas التي تضع الاستثناءات المحددة.

try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
  r.lines().forEach(System.out::println);
}

توجد أيضًا طريقة Files.lines() التي تقوم Files.lines() شيء مشابه جدًا ، Files.lines() Stream<String> مباشرة. لكنني لا أحب ذلك. يحتاج Stream إلى استدعاء close() ؛ هذا غير موثق بشكل سيئ على واجهة برمجة التطبيقات ، وأظن أن العديد من الأشخاص لا يلاحظون حتى أن Stream يمتلك طريقة close() . لذا ستبدو شفرتك متشابهة جدًا ، مثل هذا:

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

والفرق هو أن هناك Stream تم تعيينه لمتغير ، وأحاول تجنب ذلك كممارسة حتى لا أحاول استحضار الحدث مرتين.

استخدام الذاكرة

الطريقة الأولى ، التي تحافظ على فواصل الأسطر ، يمكن أن تتطلب ذاكرة عدة مرات حجم الملف مؤقتًا ، لأن لفترة قصيرة محتويات الملف الخام (صفيف بايت) ، والأحرف المشفرة (كل منها 16 بت حتى إذا تم تشفيرها كما 8 بت في الملف) الموجودة في الذاكرة في وقت واحد. من الأسلم تطبيق الملفات التي تعرف أنها صغيرة بالنسبة إلى الذاكرة المتوفرة.

الطريقة الثانية ، قراءة الأسطر ، عادة ما تكون أكثر كفاءة في الذاكرة ، لأن المخزن المؤقت للبايت المدخلات لفك التشفير لا يحتاج إلى احتواء الملف بأكمله. ومع ذلك ، فإنه لا يزال غير مناسب للملفات كبيرة جدًا بالنسبة للذاكرة المتوفرة.

لقراءة الملفات الكبيرة ، تحتاج إلى تصميم مختلف للبرنامج الخاص بك ، واحد يقرأ جزءًا من النص من جدول ، ويعالجه ، ثم ينتقل إلى التالي ، ويعيد استخدام نفس كتلة الذاكرة ذات الحجم الثابت. هنا ، يعتمد "كبير" على مواصفات الكمبيوتر. في الوقت الحاضر ، قد تكون هذه العتبة غيغا بايت من ذاكرة الوصول العشوائي. الطريقة الثالثة ، باستخدام Stream<String> هي إحدى الطرق للقيام بذلك ، إذا كانت "سجلات" الإدخال الخاصة بك تحدث خطوطًا فردية. (باستخدام الأسلوب readLine() من BufferedReader هو مكافئ إجرائي لهذا الأسلوب.)

ترميز الحروف

شيء واحد مفقود من العينة في المشاركة الأصلية هو ترميز الأحرف. هناك بعض الحالات الخاصة التي يكون فيها النظام الأساسي الافتراضي هو ما تريده ، ولكنها نادرة ، ويجب أن تكون قادرًا على تبرير اختيارك.

تعرّف فئة StandardCharsets بعض الثوابت للتشفيرات المطلوبة لكل أوقات تشغيل Java:

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

يتوفر النظام الأساسي للنظام الأساسي من فئة Charset نفسها:

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

ملاحظة: تستبدل هذه الإجابة إلى حد كبير إصدار جافا 6 الخاص بي. تقوم الأداة المساعدة Java 7 بأمان على تبسيط التعليمات البرمجية ، وتمنع الإجابة القديمة ، التي تستخدم مخزنًا مؤقتًا معينًا ، الملف الذي تمت قراءته من أن يتم حذف المخزن المؤقت المعين. يمكنك عرض النسخة القديمة عبر الرابط "المحرر" في هذه الإجابة.


لا أستطيع التعليق على المشاركات الأخرى حتى الآن ، لذلك سأتركها هنا.

واحدة من أفضل الإجابات هنا ( https://.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();
    }
}

تحاول جافا أن تكون عامة ومرنة للغاية في كل ما يفعل. نتيجة لذلك ، شيء بسيط نسبيا في لغة البرمجة النصية (سيتم استبدال رمز بك مع " open(file).read() " في بيثون) هو أكثر تعقيدا. لا يبدو أن هناك أي طريقة أقصر للقيام بذلك ، باستثناء استخدام مكتبة خارجية (مثل Willi aus Rohr المذكورة). خياراتك:

  • استخدم مكتبة خارجية.
  • انسخ هذا الرمز في جميع مشاريعك.
  • إنشاء مكتبة صغيرة خاصة بك والتي تحتوي على الوظائف التي تستخدمها في كثير من الأحيان.

رهانك الأفضل هو على الأرجح الرهان الثاني ، لأنه يحتوي على أقل تبعيات.


أيضًا إذا كان ملفك موجودًا داخل وعاء ، يمكنك أيضًا استخدام هذا:

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

يجب أن يبدأ المسار بـ / على سبيل المثال إذا كانت جرة الخاص بك

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

ثم تريد استحضاره على النحو التالي:

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

إذا كنت تبحث عن بديل لا يتضمن مكتبة طرف ثالث (مثل I / O ) ، يمكنك استخدام فئة Scanner :

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

في سطر واحد (Java 8) ، بافتراض أن لديك قارئ:

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

سيعمل هذا الرمز على تطبيع فواصل الأسطر ، والتي قد تكون أو لا تكون ما تريد فعله حقًا.

هنا هو البديل الذي لا يفعل ذلك ، والذي هو (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();
    }        
}

إذا لم يكن لديك حق الوصول إلى "الملفات" ، فيجب القيام بما يلي:

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

مع Java 7 ، هذا هو خياري المفضل لقراءة ملف UTF-8:

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

منذ Java 7 ، يحتوي JDK على واجهة برمجة التطبيقات java.nio.file الجديدة ، التي توفر العديد من الاختصارات ، لذلك لا تكون مكتبات الطرف الثالث مطلوبة دائمًا لعمليات الملفات البسيطة.


سيضيف هذا النص النصي ملف جافا سكريبت إلى أعلى أي <script>علامة أخرى :

(function () {
    var li = document.createElement('script'); 
    li.type = 'text/javascript'; 
    li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; 
    li.async=true; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(li, s);
})();




java file file-io io