อ่าน/เขียน(เป็นไบต์)และจากเป็นแฟ้มเดียวที่ใช้งานจาวา.บ io

0

คำถาม

แล้วพวกเราจะเป็นยังไงเขียนตามวันที่@item:inlistbox sort อาเรย์จะเป็นแฟ้ม(และอ่านมันหลังจากนั้นแฟ้ม)ในงานจาวา?

ใช่เราทุกคนรู้ว่ามันมีแล้วมีคำถามมากมายเหมือนอย่างนั้นแต่พวกเขาเข้ามายุ่งเหยิงและ subjective เนื่องจากความจริงที่ว่ามันมีหลายวิธีที่จะย่อมทำงานนี้.

ดังนั้นปล่อยให้เป็นลดขอบเขตของคำถาม:

โดเมน:

  • Android/ของจาวา

สิ่งที่เราต้องการ:

  • เร็ว(ที่เป็นไปได้)
  • บัฟรี(อยู่ใน rigidly พิถีพิถันทาง)

สิ่งที่เราไม่ทำ:

  • คนที่สาม-งานไลบรารี
  • มีไลบรารีที่ต้องการ Android รูปแบบ api ทีหลังว่า 23(มาร์ชแมลโลวส์)

(ดังนั้นกฏของ ปูมบันทึกของ apache Commons, ของกูเกิ้ลงฝรั่, จาวา.nioและตอนนี้เราเหลือกับ ดีมพ์ของจาวา.บ io)

สิ่งที่เราต้องการ:

  • ตามวันที่@item:inlistbox sort อาเรย์เสมอเหมือนกัน(เนื้อหาและขนาด)หลังจากผ่านการเขียน-แล้ว-อ่านโพรเซส
  • เขียนวิธีการเดียวที่ต้องการสองอาร์กิวเมนต์:แฟ้มแฟ้มและตามวันที่@item:inlistbox sort[]ข้อมูล
  • อ่านวิธีการจะได้เป็นตามวันที่@item:inlistbox sort[และเพียงต้องการรับอาร์กิวเมนต์หนึ่งตัว:แฟ้มแฟ้ม

ในของฉันโดยเฉพาะกรณีนี้เป็นวิธีการของส่วนตัว(ไม่ใช่ห้องสมุด)และ ไม่มีส่วนต้องรับผิดชอบต่อไปนี้,(แต่ถ้าคุณต้องการสร้างเป็นอีกรูปแบบสากลหาทางที่จะใช้กับต้องมีผู้ชมกว้างกไปสำหรับมัน):

  • เธรด-ความปลอดภัย(แฟ้มจะไม่ถูกรถเข้าถึงมากกว่าหนึ่งโพรเซสที่ครั้งนึง)
  • แฟ้มการโพรโทคอล aimcomment
  • แฟ้มเล็จะไม่ existent ตำแหน่ง
  • มันไม่มีสิทธิ์ที่อนุญาตอยู่ที่ตำแหน่งของแฟ้ม
  • ตามวันที่@item:inlistbox sort อาเรย์เป็นเหมือนกันใหญ่
  • ตามวันที่@item:inlistbox sort อาเรย์เป็นโพรโทคอล aimcomment
  • กำลังเจอกับอะไร"ดัชนี,""ความยาว"หรือ"เพิ่ม"อาร์กิวเมนต์/ความสามารถ

ดังนั้น...เราเป็นเหมือในการค้นหาของการวินิจฉัยขั้นสุดท้ายกระสุน-หลักฐานรหัสที่คนอื่นในอนาคตได้ว่าปลอดภัยที่จะใช้เพราะคำตอบของคุณมีหลายขึ้น-คะแนนเสียและไม่มีคำอธิบางที่บอกว่า"นั่นอาจจะตกถ้าหากว่า..."

นี่คือสิ่งที่ฉันต้องถึง:

เขียนไบต์ไปยังแฟ้ม:

private void writeBytesToFile(final File file, final byte[] data) {
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();
        } catch (Exception e) {
            Log.i("XXX", "BUG: " + e);
        }
    }

อ่านไบต์จากแฟ้ม:

private byte[] readBytesFromFile(final File file) {
        RandomAccessFile raf;
        byte[] bytesToReturn = new byte[(int) file.length()];
        try {
            raf = new RandomAccessFile(file, "r");
            raf.readFully(bytesToReturn);
        } catch (Exception e) {
            Log.i("XXX", "BUG: " + e);
        }
        return bytesToReturn;
}

จากสิ่งที่ฉันได้อ่านหนังสือที่เป็นไปได้ข้อยกเว้นเป็น:

FileNotFoundException:ฉันถูกต้องว่านี่จะไม่เกิดขึ้นนานเท่าที่แฟ้มเส้นทางถูกจัดให้เป็น derived ใช้ Android ของตัวเองภายในเครื่องมือและ/หรือแอพฯถูกทดสอบอย่างเหมาะส?

IOException:ฉันไม่รู้จริงๆว่ามีอะไรเพราะนี่...แต่ฉันสันนิษฐานว่ามันไม่มีทางอยู่ถ้ามันมี

ดังนั้นกับมันอยู่ในใจ...ได้พวกนี้เป็นวิธีการของปรับปรุงหรือแทนที่และถ้าอย่างนั้นกับอะไร?

android arrays file java
2021-11-23 02:58:43
2

คำตอบที่ดีที่สุด

6

มันดูเหมือนพวกนี้กำลังจะเป็นแกนกลางเครื่องมือ/ห้องสมุดวิธีการของซึ่งต้องวิ่งบน Android รูปแบบ api 23 หรือทีหลัง

เรื่องของห้องสมุดวิธีการของฉันเจอมันที่ดีที่สุดที่จะไม่ตั้งสมมติฐานว่าโปรแกรมจะใช้วิธีการของพวกนี้. ในบางกรณีที่โปรแกรมอาจจะต้องได้รับเช็ค IOExceptions(เพราะข้อมูลจากแฟ้มต้องมีตัวตนสำหรับโปรแกรมที่ทำงาน)ในคดีอื่นที่โปรแกรมอาจจะไม่แม้แต่สนใจว่าข้อมูลไม่สามารถรับสาย(เพราะข้อมูลจากแฟ้มเป็นเพียงแคชของมันยังใช้ได้จากกลุ่มหลักแหล่งข่าว).

เมื่อมันมาพร้อมต้อง i/O ปฏิบัติการนั่นคือไม่เคยรับประกันว่าปฏิบัติการท่านจะประสบความสำเร็จ(e.g. ของผู้ใช้ทิ้งโทรศัพท์ในห้องน้ำ). ห้องสมุดควรจะได้ไตร่ตรองนั่นและทำให้โปรแกรมที่เลือกการจัดการกับข้อผิดพลาด.

ต้อง the result will be artificially smoothed to hide jpeg artefacts i/O การแสดงอยู่เสมองสันนิษฐานว่า"มีความสุขเส้นทางและจับข้อผิดพลาดที่จะคิดให้ออกอะไรคือสิ่งที่เค้าจึงสั่งฆ่าพวกเราทั้งหมด นี่เป็นเคาน์เตอร์ intuitive เป็นปกติตั้งโปรแกรมแต่สิ่งสำคัญมากของอยู่ในลังรับมือกับห้องเก็บของ i/O สำหรับตัวอย่างเช่นแค่กำลังตรวจสอบว่ามีแฟ้มอยู่ก่อนก่อนที่อ่านจากแฟ้มสามารถทำให้โปรแกรมของคุณสองครั้งที่ช้าทั้งหมดนี้เป็นของฉัน/โองการกระทำเพิ่มขึ้นเร็วมากที่จะชะลอโปรแกรมของคุณลงไป แค่สันนิษฐานว่ามีแฟ้มอยู่ก่อนแล้วและถ้าคุณได้ข้อผิดพลาดเกิดขึ้นระหว่างเพียงนั้นโปรดตรวจสอบว่ามีแฟ้มอยู่ก่อนแล้ว

งั้นให้พวกนั้นความคิดหลักฟังก์ชันอาจจะดูเหมือน:

public static void writeFile(File f, byte[] data) throws FileNotFoundException, IOException {
    try (FileOutputStream out = new FileOutputStream(f)) {
        out.write(data);
    }
}

public static int readFile(File f, byte[] data) throws FileNotFoundException, IOException {
    try (FileInputStream in = new FileInputStream(f)) {
        return in.read(data); 
    }
}

บันทึกเกี่ยวกับที่ implementation:

  • ในวิธีการของยังสามารถโยน runtime-ข้อยกเว้นเหมือน NullPointerExceptions-วิธีการของพวกนี้ไม่เคยจะต้อง"แมส".
  • ฉันไม่คิดว่า buffering เป็นต้องการ/ต้องการในวิธีการของเหนือตั้งแต่เดียวที่เป็นชนพื้นเมืองที่เรียกเสร็จแล้ว (เห็นยัง อยู่ที่นี่).
  • โปรแกรมตอนนี้ก็ยังคงมีตัวเลือกนี้เพื่ออ่านได้อย่างเดียวจุดเริ่มต้นของแฟ้ม

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

public static byte[] readFile(File f) throws FileNotFoundException, IOException {
    int fsize = verifyFileSize(f);
    byte[] data = new byte[fsize];
    int read = readFile(f, data);
    verifyAllDataRead(f, data, read);
    return data;
}

private static int verifyFileSize(File f) throws IOException {
    long fsize = f.length();
    if (fsize > Integer.MAX_VALUE) {
        throw new IOException("File size (" + fsize + " bytes) for " + f.getName() + " too large.");
    }
    return (int) fsize;
}

public static void verifyAllDataRead(File f, byte[] data, int read) throws IOException {
    if (read != data.length) {
        throw new IOException("Expected to read " + data.length 
                + " bytes from file " + f.getName() + " but got only " + read + " bytes from file.");
    }
}

นี่ implementation เพิ่มอีกซ่อนอยู่ประเด็นของความล้มเหลว:OutOfMemory ที่ประเด็นที่ใหม่ของข้อมูลอาเรย์ถูกสร้างไว้

บรรลุข้อตกลงโปรแกรมเพิ่มเติม,เพิ่มเติมวิธีการของจะถูกเพิ่มเข้ากับช่วยเรื่องแตกต่างสร้างสถานการณ์จำลอง ตัวอย่างเช่นกันเอาเป็นว่าของโปรแกรมจริงๆไม่ต้องการที่จะจัดการกับเช็คข้อยกเว้น:

public static void writeFileData(File f, byte[] data) {
    try {
        writeFile(f, data);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
}

public static byte[] readFileData(File f) {
    try {
        return readFile(f);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
    return null;
}

public static int readFileData(File f, byte[] data) {
    try {
        return readFile(f, data);
    } catch (Exception e) {
        fileExceptionToRuntime(e);
    }
    return -1;
}

private static void fileExceptionToRuntime(Exception e) {
    if (e instanceof RuntimeException) { // e.g. NullPointerException
        throw (RuntimeException)e;
    }
    RuntimeException re = new RuntimeException(e.toString());
    re.setStackTrace(e.getStackTrace());
    throw re;
}

จากวิธีการ fileExceptionToRuntime เป็นขนาดเล็กที่สุด implementation แต่มันแสดงถึงความคิดอยู่ที่นี่

ห้องสมุดอาจช่วยโปรแกรมที่จะ troubleshoot ตอนที่ข้อผิดพลาดเกิดขึ้นระหว่างมันเกิดขึ้น. ตัวอย่างเช่นเป็นวิธีการ canReadFile(File f) ได้โปรดตรวจสอบว่ามีแฟ้มอยู่ก่อนและเป็นสามารถอ่านและมันไม่ใหญ่เกินไป โปรแกรมจะเรียกเช่นฟังก์ชันหลังจากแฟ้ม-อ่านความผิดพลาดและเช็คสำหรับเหมือนกันด้วยเหตุผลทำไมมีแฟ้มไม่สามารถอ่านได้ เหมือนจะเป็นไปสำหรับการเขียนไปยังแฟ้ม

2021-11-28 22:59:55

ขอบคุณที่ช่วยและได้รับข้อมูลมากเลยทีเดีคำตอบ ผมทิ้งมันด้วยกันในโครงการจะเห็นถ้าฉันสามารถเข้าใจมันดีขึ้น อะไรคือเหตุผลสำหรับการเปลี่ยน readBytes วิธีการลายเซ็นจากอะไรฉัน? (ของคุณต้องใช้ตามวันที่@item:inlistbox sort[]คนใดคนหนึ่งที่ args และจะคืนค่าเป็น int). ก็คือสุดท้ายของคุณบล็อกของรหัสความตั้งใจที่จะเป็นส่วนหนึ่งของห้องสมุดหรือโปรแกรม?
Nerdy Bunz

ยังไม่ร"กลับไป(int)f.ความยาว();"ชนตั้งแต่เอฟ.เคเนดี้ความยาวมีขนาดใหญ่กว่าเป็นเลขจำนวนเต็มMAX_VALUE?
Nerdy Bunz

@NerdyBunz เรื่องแล้วมันเกิดอะไรขึ้นไม่ได้"downcasting"ไม่ให้เกิดข้อผิดพลาดและในกรณีนี้,เป็น IOException ขึ้นตอนที่ fsize คืนค่าขนาดใหญ่เกินไป. แล้วฉันควรจะกลัใช้ fsize มี(ตั้งแต่ f.length() ผลตรวจในส่วน i/O ปฏิบัติการ).
vanOekel

เรื่องแรกที่คำถามทั้งหมดของมันมีความตั้งใจที่จะเป็นส่วนหนึ่งของห้องสมุด ของฉัน byte[] readFile(File f) คืนที่คล้ายกันของคุณ byte[] readBytesFromFile(final File file). ของฉัน byte[] readFileData(File f) วิธีการเป็นตัวอย่างของคุณสามารถทำการปรับแต่งแก้ไขได้พวกนี้ฟังก์ชันทางไปได้ไกลกว่านี้ ฉันมีปัญหาการแก้ปัญหาออกไปซึ่งวิธีการขอที่จะเปิดเผย(publicและเก็บซ่อน(privateและฉันคิดว่านั่นเป็นคำถามเดียวที่คุณสามารถตอบ:ซึ่งวิธีการของคุณต้องการจะให้โปรแกรมที่จะใช้โดยไม่ต้องการข้อจำกัดเยอะต้องของโปรแกรม?
vanOekel
3

ถึงแม้ว่าคุณไม่สามารถใช้คนที่สามงานไลบรารี,คุณยังสามารถอ่านของรหัสและเรียนรู้จากพวกเขาประสบการณ์นะ ในของกูเกิ้ลงฝรั่ตัวอย่างเช่นคุณมักจะอ่านแฟ้มในไบต์แบบนี้:

FileInputStream reader = new FileInputStream("test.txt");
byte[] result = ByteStreams.toByteArray(reader);

แกนหลักของ implementation ของเรื่องนี้ toByteArrayInternal. ก่อนที่โทรมาเรื่องนี้คุณควรจะตรวจสอบ:

  • เป็นไม่ใช่โพรโทคอล aimcomment แฟ้มผ่าน(NullPointerException)
  • แฟ้มอยู่ก่อน(FileNotFoundException)

หลังจากนั้นมันถูกลดขนาดลงเหลือการจัดการการ InputStream และนี่อยู่ไหน IOExceptions จากมา ตอนที่อ่านทั่วลำน้ำหลายอย่างออกจากควบคุมของโปรแกรมของคุณสามารถผิดพลาดร้าย sectors และอื่นๆของฮาร์ดแวร์ปัญหา mal-ทำหน้าที่ได้ขับรถ,O เข้าถึงสิทธิ์ของ)และจงปรากฏตัวเองกับ IOException.

ฉันคือการคัดลอกที่นี่ implementation:

private static final int BUFFER_SIZE = 8192;

/** Max array length on JVM. */
private static final int MAX_ARRAY_LEN = Integer.MAX_VALUE - 8;

private static byte[] toByteArrayInternal(InputStream in, Queue<byte[]> bufs, int totalLen)
      throws IOException {
    // Starting with an 8k buffer, double the size of each successive buffer. Buffers are retained
    // in a deque so that there's no copying between buffers while reading and so all of the bytes
    // in each new allocated buffer are available for reading from the stream.
    for (int bufSize = BUFFER_SIZE;
        totalLen < MAX_ARRAY_LEN;
        bufSize = IntMath.saturatedMultiply(bufSize, 2)) {
      byte[] buf = new byte[Math.min(bufSize, MAX_ARRAY_LEN - totalLen)];
      bufs.add(buf);
      int off = 0;
      while (off < buf.length) {
        // always OK to fill buf; its size plus the rest of bufs is never more than MAX_ARRAY_LEN
        int r = in.read(buf, off, buf.length - off);
        if (r == -1) {
          return combineBuffers(bufs, totalLen);
        }
        off += r;
        totalLen += r;
      }
    }

    // read MAX_ARRAY_LEN bytes without seeing end of stream
    if (in.read() == -1) {
      // oh, there's the end of the stream
      return combineBuffers(bufs, MAX_ARRAY_LEN);
    } else {
      throw new OutOfMemoryError("input is too large to fit in a byte array");
    }
  }

อย่างที่คุณสามารถเห็นส่วนใหญ่ของตรรกะที่ต้องมีส่วนเกี่ยวข้องกับการอ่านแฟ้มในท่อน. นี่คือที่จะจัดการสถานการณ์ที่คุณไม่รู้จักขนาดของ InputStream ก่อนที่จะเริ่มอ่านอยู่ ในกรณีของคุณคุณแค่ต้องการจะอ่านแฟ้มและคุณควรจะรู้ความยาวขึ้นแล้วนี่มีความซับซ้อนอาจจะเลี่ยงไม่.

คนอื่นดูเป็น OutOfMemoryException. ในมาตรฐานของจาวาที่จำกัดเป็นเหมือนกันใหญ่อย่างไรก็ตามใน Android มันจะเป็นกตัวเล็กลงค่า. คุณควรจะตรวจสอบก่อนที่พยายามที่จะอ่านแฟ้มที่มีอยู่ เพียงพอความทรงจำที่มีอยู่.

2021-11-26 13:42:23

ในภาษาอื่นๆ

หน้านี้อยู่ในภาษาอื่นๆ

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................