APP中读写可编辑扩展的二维String数组至TXT文件的问题
Hey there! Let's tackle your problem head-on—you want to save, load, edit, and extend a 2D String array in your Android app, you're hitting a NullPointerException with BufferedWriter/BufferedReader, and you're curious about using FileInputStream/FileOutputStream too. Let's break this down step by step.
First: Why That NullPointerException?
NPE with stream classes almost always boils down to one of these common issues:
- Invalid File Path: You're trying to write to a location your app doesn't have access to, or the path is incorrect (e.g., hardcoding a path like
/sdcard/instead of using Android's storage APIs). - Uninitialized Stream Objects: You might be trying to call methods on a
BufferedWriter/BufferedReaderthat wasn't properly instantiated (e.g.,new BufferedWriter(null)because the underlyingFileWriterfailed to create). - Missing Permissions: On older Android versions (pre-10), you need the
WRITE_EXTERNAL_STORAGEpermission, and on Android 6+, you have to request it dynamically.
Always double-check that your File object points to a valid, writable location—use context.getExternalFilesDir(null) or context.filesDir for app-private storage (no permissions needed on Android 10+).
Solution 1: Using BufferedReader/BufferedWriter (Character Streams)
Character streams are ideal for text data like Strings. Here's a robust implementation:
Save the 2D Array
public void save2DArray(Context context, String[][] array, String fileName) { File file = new File(context.getExternalFilesDir(null), fileName); try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { // Write each row as a line, with elements separated by a delimiter (e.g., "||") for (String[] row : array) { String line = String.join("||", row); writer.write(line); writer.newLine(); } } catch (IOException e) { e.printStackTrace(); // Handle error (e.g., show toast to user) } }
Load the 2D Array
public String[][] load2DArray(Context context, String fileName) { File file = new File(context.getExternalFilesDir(null), fileName); if (!file.exists()) { return new String[0][0]; // Or return your default array } List<String[]> rowsList = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; while ((line = reader.readLine()) != null) { // Split each line back into elements using the same delimiter String[] row = line.split("\\|\\|"); // Escape the delimiter since | is a regex special char rowsList.add(row); } } catch (IOException e) { e.printStackTrace(); } // Convert List to 2D array return rowsList.toArray(new String[rowsList.size()][]); }
Editing & Extending the Array
Once loaded, convert the 2D array to an ArrayList<String[]> for easy modifications:
// Load existing array String[][] loadedArray = load2DArray(context, "myArray.txt"); // Convert to ArrayList for flexibility ArrayList<String[]> arrayList = new ArrayList<>(Arrays.asList(loadedArray)); // Add a new row arrayList.add(new String[]{"New Item 1", "New Item 2"}); // Edit an existing element if (arrayList.size() > 0) { arrayList.get(0)[0] = "Updated Value"; } // Save the modified array back to file save2DArray(context, arrayList.toArray(new String[arrayList.size()][]), "myArray.txt");
Solution 2: Using FileInputStream/FileOutputStream (Byte Streams)
Byte streams work with raw bytes, so we'll need to convert our String data to bytes (and vice versa) using a consistent encoding like UTF-8.
Save with FileOutputStream
public void save2DArrayWithByteStream(Context context, String[][] array, String fileName) { File file = new File(context.getExternalFilesDir(null), fileName); try (FileOutputStream fos = new FileOutputStream(file)) { StringBuilder sb = new StringBuilder(); for (String[] row : array) { sb.append(String.join("||", row)).append("\n"); } // Convert string to bytes and write fos.write(sb.toString().getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { e.printStackTrace(); } }
Load with FileInputStream
public String[][] load2DArrayWithByteStream(Context context, String fileName) { File file = new File(context.getExternalFilesDir(null), fileName); if (!file.exists()) { return new String[0][0]; } List<String[]> rowsList = new ArrayList<>(); try (FileInputStream fis = new FileInputStream(file)) { // Read all bytes and convert to string byte[] bytes = new byte[(int) file.length()]; fis.read(bytes); String content = new String(bytes, StandardCharsets.UTF_8); // Split content into lines and parse rows String[] lines = content.split("\n"); for (String line : lines) { if (!line.isEmpty()) { // Skip empty lines rowsList.add(line.split("\\|\\|")); } } } catch (IOException e) { e.printStackTrace(); } return rowsList.toArray(new String[rowsList.size()][]); }
Key Notes for Android
- Storage Location: Always use app-private storage (
getExternalFilesDirorfilesDir) to avoid permission issues and ensure your data is deleted when the app is uninstalled. - Exception Handling: Don't just print stack traces—notify the user if save/load fails (e.g., with a Toast or Snackbar).
- Delimiter Choice: Pick a delimiter that won't appear in your actual String data (e.g.,
||instead of,if your strings might contain commas).
内容的提问来源于stack exchange,提问作者Blood_Working

