Android应用首次运行无法复制文件至SD卡,二次运行正常求解决
Hey there, let's figure out why your file copy only works on the second app launch. Based on your code snippet and description, here are the most likely causes and fixes:
1. Incomplete Folder/File Check Logic
Your code only checks if the target folder exists, but doesn't verify if the destination file bor.pak is already present (or was partially copied in the first run). Also, you might not be handling cases where folder creation fails silently.
Fix Suggestion:
Add full checks for both folder creation success and file existence, then execute the copy only when needed:
private void CopyPak() { try { InputStream in = getResources().openRawResource(R.raw.bor); File outFolder = new File(Environment.getExternalStorageDirectory() + "/OpenBOR/Paks"); File outFile = new File(outFolder, "bor.pak"); // Skip copy if file already exists if (outFile.exists()) { in.close(); return; } // Create folder and check if creation succeeded if (!outFolder.exists()) { boolean folderCreated = outFolder.mkdirs(); if (!folderCreated) { Log.e("CopyPak", "Failed to create folder: " + outFolder.getAbsolutePath()); in.close(); return; } } // Perform the file copy FileOutputStream out = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int readBytes; while ((readBytes = in.read(buffer)) != -1) { out.write(buffer, 0, readBytes); } // Always close streams in the right order out.flush(); out.close(); in.close(); Log.d("CopyPak", "File copied successfully!"); } catch (IOException e) { e.printStackTrace(); Log.e("CopyPak", "Copy failed: " + e.getMessage()); } }
2. Missing Dynamic Permission Handling (Android 6.0+)
On Android 6.0 (API 23) and above, WRITE_EXTERNAL_STORAGE is a dangerous permission that requires dynamic request. The first launch might fail because the user hasn't granted permission yet, while the second launch works after permission is granted.
Fix Suggestion:
Check and request storage permission before calling CopyPak():
private static final int STORAGE_PERMISSION_REQUEST = 1001; // Call this method instead of directly calling CopyPak() private void prepareCopy() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_REQUEST); } else { CopyPak(); } } // Handle permission request result @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERMISSION_REQUEST) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { CopyPak(); } else { Toast.makeText(this, "Storage permission is required to copy the file", Toast.LENGTH_SHORT).show(); } } }
Note: For Android 10+ (API 29), Environment.getExternalStorageDirectory() is restricted. Use app-specific external storage instead to avoid permission issues:
File outFolder = new File(getExternalFilesDir(null), "/OpenBOR/Paks");
3. Unclosed Streams Causing Incomplete Files
If your original code didn't properly close input/output streams, the first copy might produce an incomplete file that the system doesn't recognize. The second run would re-copy the file correctly if the stream is closed properly this time.
Fix Suggestion:
Use try-with-resources (Java 7+) to auto-close streams:
private void CopyPak() { try (InputStream in = getResources().openRawResource(R.raw.bor)) { File outFolder = new File(Environment.getExternalStorageDirectory() + "/OpenBOR/Paks"); File outFile = new File(outFolder, "bor.pak"); if (outFile.exists()) return; if (!outFolder.exists() && !outFolder.mkdirs()) { Log.e("CopyPak", "Failed to create folder"); return; } try (FileOutputStream out = new FileOutputStream(outFile)) { byte[] buffer = new byte[1024]; int readBytes; while ((readBytes = in.read(buffer)) != -1) { out.write(buffer, 0, readBytes); } out.flush(); Log.d("CopyPak", "Copy successful"); } } catch (IOException e) { e.printStackTrace(); Log.e("CopyPak", "Error during copy: " + e.getMessage()); } }
Start by checking the permission and stream closure issues first—these are the most common culprits for this kind of problem. If you still run into issues, share your full CopyPak() code and logcat output for deeper analysis.
内容的提问来源于stack exchange,提问作者malik

