Android Studio中TCP套接字发送文件触发FileNotFoundException(权限被拒)
Hey, let's work through this issue you're facing—even with manifest permissions set up, it's super common to hit this permission/ file not found snag on Android. Here are the most likely fixes to try:
1. You're Missing Runtime Permission Requests (Critical for API 23+)
Android 6.0 and above require you to ask users for dangerous permissions at runtime, not just list them in the manifest. If you're accessing audio files on external storage, you need explicit user approval before trying to read the file.
Here's how to handle this in your MainActivity:
- For apps targeting SDK 33+: Use
READ_MEDIA_AUDIOinstead of the old storage permissions - For older targets: Use
READ_EXTERNAL_STORAGE
Add this code to check and request permissions before starting your Server function:
private val PERMISSION_REQUEST_CODE = 123 private val requiredPermissions: Array<String> get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { arrayOf(Manifest.permission.READ_MEDIA_AUDIO) } else { arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE) } private fun setupPermissions() { val missingPermissions = requiredPermissions.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED } if (missingPermissions.isNotEmpty()) { ActivityCompat.requestPermissions( this, missingPermissions.toTypedArray(), PERMISSION_REQUEST_CODE ) } else { // Permissions are good—start your server logic startYourServerFunction() } } // Handle the permission request result override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { startYourServerFunction() } else { Toast.makeText(this, "Need audio access permission to send files!", Toast.LENGTH_SHORT).show() } } }
Call setupPermissions() when your activity starts (like in onCreate()) instead of directly calling your Server function.
2. Scoped Storage is Blocking Access (Android 10+)
Starting with Android 10 (API 29), scoped storage prevents apps from directly accessing most files on external storage via absolute paths—even with storage permissions.
Quick Fixes:
- For API 29-30: Add
android:requestLegacyExternalStorage="true"to your<application>tag inAndroidManifest.xml. This lets your app use the old storage model temporarily. - For API 31+:
- Use the
MediaStoreAPI to query and get the URI of your audio file instead of hardcoding paths. This is the recommended way to access media files now. - If you need full access to external storage (only for file manager-style apps), request
MANAGE_EXTERNAL_STORAGE—but note this requires sending users to your app's settings to enable it (you can't get it via a normal permission dialog).
- Use the
3. Your File Path is Wrong (Or the File Doesn't Exist)
Even with perfect permissions, if you're pointing to a file that doesn't exist, you'll get FileNotFoundException. Add these checks before trying to read the file:
val audioFile = File("/your/supposed/audio/path.mp3") Log.d("AudioCheck", "Checking file at: ${audioFile.absolutePath}") if (!audioFile.exists()) { Log.e("AudioCheck", "File doesn't exist!") return } if (!audioFile.canRead()) { Log.e("AudioCheck", "Can't read the file—permission issue even after grants?") return }
Printing the absolute path will help you confirm if you're targeting the right location (maybe you used a relative path that's not resolving correctly, or the file was moved/deleted).
4. Mixing Up Private vs. External Storage
If the audio file is stored in your app's private directory (like getFilesDir() or getCacheDir()), you don't need external storage permissions—but make sure you're using the correct path to access it. Private storage is only accessible by your app, so double-check you didn't accidentally use an external storage path for a private file.
内容的提问来源于stack exchange,提问作者Alex Murphy

