จะบันทึกไฟล์ด้วย File API ไปยังตำแหน่งที่ผู้ใช้เลือกใน Android 11 ได้อย่างไร

ฉันสับสนมากกับ Scoped Storage และ Storage Access Framework (SAF) และข้อจำกัดทั้งหมด .. ฉันต้องใช้ File API ไม่ใช่ Uri ดังนั้น:
ระดับ Android API ‹= 29 (Android 10) บันทึกเป็น /storage/emulated/0 ใช้งานได้ (ด้วย requestLegacyExternalStorage)
ระดับ Android API = 30 (Android 11) บันทึกไปที่ /storage/emulated/0 ไม่ทำงาน (IOException: Operation not permitted)

Environment.getExternalStorageDirectory() เลิกใช้แล้ว ตกลง งั้น getExternalFilesDirs() ใน Android 11:

ctx.getExternalFilesDirs(): /storage/emulated/0/Android/data/<package name>/files //External storage in internal memory
ctx.getExternalFilesDirs(): /storage/16F4-3A1C/Android/data/<package name>/files //SDcard

ใช้งานได้เพราะเป็นที่เก็บข้อมูลของแอป แต่ผู้ใช้ต้องการให้โฟลเดอร์ของแอปอยู่ในรูทของที่จัดเก็บข้อมูลภายนอก /storage/emulated/0/MySpecificFolder หรือ sdcard /storage/16F4-3A1C/MySpecificFolder ฉันกำลังทำงานกับ File API ซึ่งน่าจะใช้งานได้อีกครั้ง (ต่างจาก Android10)

ฉันจะเขียนไปยังไดเร็กทอรีเฉพาะของผู้ใช้ เช่น /storage/emulated/0/MySpecificFolder ได้อย่างไร

ฉันพยายามใช้:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, PICK_FOLDER);

ซึ่งเปิดตัวจัดการไฟล์ ผู้ใช้สร้างไดเร็กทอรีใหม่ (เนื่องจากรูทไม่สามารถใช้งานได้): /storage/emulated/0/MySpecificFolder ต่อไปฉันกำลังลองสร้างไฟล์ใหม่ผ่าน:

File nomedia = new File("/storage/emulated/0/MySpecificFolder", ".nomedia");
if (!nomedia.exists()) {
    nomedia.createNewFile();
}

แต่มันใช้งานไม่ได้ IOException: Operation not permitted อาจมีปัญหากับการอนุญาตการเขียน

บรรทัดนี้ใช้งานได้:

DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");

ซึ่งใช้ได้กับ Uri เหตุใดจึงใช้ File API ไม่ได้ เมื่อฉันโทร createFile() ซึ่งใช้ Uri นั่นได้ผล แต่เมื่อฉันโทร createNewFile() ซึ่งใช้ File API นั่นไม่ทำงาน ดังนั้นผู้ใช้สามารถเลือกไดเร็กทอรีของตัวเองได้ แต่เมื่อแอปทำงานกับ Uri เท่านั้น

วิธีรับ path (สำหรับใช้ในภายหลังกับ File API) จาก SAF ไม่ใช่แค่ Uri

// Get Uri from Storage Access Framework.
Uri treeUri = data.getData();
DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
Log.i(TAG, "Tree uri: "+treeUri.getPath());  //returns /tree/primary:My
Log.i(TAG, "Picked dir: "+pickedDir.getUri().getPath()); //returns /tree/primary:My/document/primary:My

ฉันต้องใช้ File API เพราะแอป สร้างไฟล์วิดีโอ+รูปภาพ+ข้อมูลซึ่งจำเป็นต้องรวมเข้าด้วยกัน

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


comment
ฉันต้องใช้ File API เพราะแอป สร้างไฟล์วิดีโอ+ภาพถ่าย+ข้อมูลซึ่งจำเป็นต้องอยู่ด้วยกัน -- สร้างไฟล์เหล่านั้นใน getFilesDir() จากนั้นคัดลอกไปยังแผนผังเอกสารที่ผู้ใช้เลือก หรือเลือก SDK ที่ช่วยให้คุณทำงานกับสตรีมแทนไฟล์ได้ เป็นไปได้ไหมที่ผู้ใช้จะเลือกเส้นทางของตัวเอง + สร้างโฟลเดอร์ (ผ่าน SAF อาจ) และส่งคืนไฟล์ (ตัวอธิบายไฟล์) ของโฟลเดอร์ที่สร้างขึ้นใหม่โดยผู้ใช้ไปยังแอป -- ไม่ใช่ File คุณสามารถรับตัวอธิบายไฟล์สำหรับ Uri ผ่าน ContentResolver   -  person CommonsWare    schedule 16.12.2020
comment
บางทีนี่อาจเป็นสิ่งที่คุณต้องการ: github.com/anggrayudi/SimpleStorage   -  person Anggrayudi H    schedule 18.12.2020


คำตอบ (1)


บน Android 11 ทุกแอปสามารถเขียนไปยังไดเร็กทอรีสาธารณะบนที่จัดเก็บข้อมูลภายนอกโดยใช้คลาสไฟล์แบบเก่า

อย่าปล่อยให้ผู้ใช้เลือกสถานที่ จากนั้นสำหรับการดำเนินการเพิ่มเติมที่คุณต้องการ คุณต้องใช้ SAF

หากคุณต้องการให้ผู้ใช้เลือกระหว่างเอกสาร ดาวน์โหลด สัญญาณเตือน DCIM รูปภาพ และอื่นๆ ให้ใช้รายการขนาดเล็กที่มีตัวสร้างการแจ้งเตือน

person blackapps    schedule 16.12.2020