พื้นที่เก็บข้อมูลภายในของแอปคือพื้นที่เฉพาะบนอุปกรณ์ที่สามารถเข้าถึงได้เฉพาะแอปพลิเคชันใดแอปหนึ่งผ่านพื้นที่เก็บข้อมูลแบบแยกส่วน ตาม Android Developers, 2026 แอปพลิเคชันแต่ละรายการจะได้รับไดเรกทอรีแซนด์บ็อกซ์ของตนเองซึ่งแอปพลิเคชันอื่นไม่สามารถเข้าถึงโดยตรงได้ แนวทางนี้ช่วยปกป้องข้อมูลจากการอ่านโดยไม่ได้รับอนุญาตและรับประกันการทำงานที่เสถียรในสภาพแวดล้อมแบบมัลติทาสก์ของอุปกรณ์มือถือ
ประเด็นสำคัญ
Context.getFilesDir(), getCacheDir() และ getDataDir() สำหรับเข้าถึงพื้นที่เก็บข้อมูลภายในNSDocumentDirectory และ NSCachesDirectory ในคอนเทนเนอร์แซนด์บ็อกซ์ของแอปพื้นที่เก็บข้อมูลภายในของแอปคือไดเรกทอรีแบบแยกส่วนที่ระบบปฏิบัติการจัดสรรให้แต่ละแอปพลิเคชันระหว่างการติดตั้ง แอปพลิเคชันอื่นและผู้ใช้ไม่สามารถเข้าถึงไดเรกทอรีนี้ผ่านตัวจัดการไฟล์มาตรฐานได้ ระบบรับประกันว่าข้อมูลทั้งหมดภายในไดเรกทอรีนี้จะถูกลบอย่างสมบูรณ์เมื่อถอนการติดตั้งแอปพลิเคชัน แนวทางนี้เป็นพื้นฐานของโมเดลความปลอดภัยของระบบปฏิบัติการมือถือ ป้องกันการรั่วไหลของข้อมูลที่เป็นความลับระหว่างโปรแกรม
ต่างจากพื้นที่เก็บข้อมูลภายนอก (การ์ด SD) พื้นที่เก็บข้อมูลภายในพร้อมใช้งานเสมอและไม่ต้องตรวจสอบว่ามีสื่อบันทึกข้อมูลหรือไม่ ความเร็วในการอ่านและเขียนในหน่วยความจำแฟลช NAND ของอุปกรณ์สมัยใหม่สูงถึง 800–900 MB/s สำหรับการอ่านแบบเรียงลำดับและ 200–300 MB/s สำหรับการเขียนแบบเรียงลำดับ ซึ่งเทียบได้กับ SSD แบบ SATA ขนาดของพื้นที่ที่จัดสรรขึ้นอยู่กับความจุรวมของอุปกรณ์และนโยบายของผู้ผลิต: บนอุปกรณ์ที่มีหน่วยความจำแฟลช 64 GB แอปจะได้รับพื้นที่เริ่มต้น 16 ถึง 64 MB โดยสามารถขยายได้ตามความจำเป็น
สถาปัตยกรรมพื้นที่เก็บข้อมูลภายในแตกต่างกันระหว่าง Android และ iOS บน Android แอปพลิเคชันแต่ละรายการจะได้รับไดเรกทอรี /data/data/<package_name>/ ซึ่งภายในระบบจะสร้างไดเรกทอรีย่อย files/, cache/ และ databases/ บน iOS แอปพลิเคชันทำงานในคอนเทนเนอร์แซนด์บ็อกซ์ที่มีไดเรกทอรี Documents/, Library/ และ tmp/ โดยแต่ละไดเรกทอรีมีวัตถุประสงค์และนโยบายสำรองข้อมูลของตนเอง
นักพัฒนามีหลายวิธีในการบันทึกข้อมูลในพื้นที่เก็บข้อมูลภายในของแอป แต่ละวิธีแก้ปัญหางานเฉพาะและเหมาะกับข้อมูลบางประเภท การเลือกวิธีที่ถูกต้องส่งผลโดยตรงต่อประสิทธิภาพของแอปพลิเคชัน ความสะดวกในการพัฒนา และความปลอดภัยของข้อมูลผู้ใช้
วิธีระดับต่ำที่สุดคือการเขียนไฟล์โดยตรงไปยังไดเรกทอรีไฟล์ แอปสามารถสร้างไฟล์และไดเรกทอรีใดก็ได้ภายในแซนด์บ็อกซ์ของตน วิธีนี้เหมาะสำหรับการจัดเก็บไฟล์สื่อ เอกสารผู้ใช้ และข้อมูลไบนารีใด ๆ ที่ไม่ต้องการการจัดระเบียบที่มีโครงสร้าง บน Android การเข้าถึงไดเรกทอรีทำได้ผ่านการเรียก Context.getFilesDir() ซึ่งส่งคืนพาธสัมบูรณ์ไปยังไดเรกทอรีไฟล์ของแอป บน iOS ฟังก์ชัน NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ทำหน้าที่คล้ายกัน
สำหรับการจัดเก็บคู่คีย์-ค่า Android มี SharedPreferences และ DataStore ที่ทันสมัยกว่าซึ่งอิงจากโครูทีน Kotlin และโปรโตคอล protobuf SharedPreferences จัดเก็บข้อมูลในไฟล์ XML ภายในไดเรกทอรี /data/data/<package>/shared_prefs/ แม้จะใช้งานง่าย แต่ SharedPreferences มีข้อเสีย: การเขียนแบบซิงโครนัสอาจทำให้เกิดความล่าช้าบนเธรด UI และการขาดความปลอดภัยของประเภทเพิ่มความเสี่ยงของข้อผิดพลาด DataStore แก้ปัญหาเหล่านี้โดยให้ API แบบอะซิงโครนัสที่อิงจาก Flow และการสนับสนุนประเภทอย่างสมบูรณ์ผ่านสคีมา protobuf
สำหรับข้อมูลที่มีโครงสร้างพร้อมความสัมพันธ์เชิงเชื่อมโยง ตัวเลือกที่เหมาะสมที่สุดคือ SQLite หรือตัวห่อหุ้ม Room ฐานข้อมูลถูกจัดเก็บในไฟล์เดียวภายในไดเรกทอรี databases/ และรองรับไวยากรณ์ SQL อย่างสมบูรณ์ Room เป็นไลบรารี Jetpack อย่างเป็นทางการที่ให้ API ที่ปลอดภัยต่อประเภท การโยกย้ายสคีมาอัตโนมัติ และการสนับสนุนโครูทีน ขนาดฐานข้อมูลสามารถเข้าถึงหลายกิกะไบต์โดยไม่สูญเสียประสิทธิภาพอย่างมีนัยสำคัญหากมีการจัดทำดัชนีอย่างเหมาะสม SQLite บนอุปกรณ์มือถือสามารถจัดการการเขียนได้ถึง 50,000 ครั้งต่อวินาทีบนโปรเซสเซอร์เรือธงสมัยใหม่
สำหรับการจัดเก็บข้อมูลที่เป็นความลับ เช่น โทเคนการตรวจสอบสิทธิ์และคีย์การเข้ารหัส Android มี EncryptedSharedPreferences ตัวห่อหุ้มนี้เหนือ SharedPreferences มาตรฐานจะเข้ารหัสคีย์และค่าโดยอัตโนมัติโดยใช้ AES256-GCM-None การเข้ารหัสจะดำเนินการที่ระดับไฟล์ก่อนเขียนลงดิสก์ ดังนั้นแม้จะเข้าถึงอุปกรณ์ทางกายภาพ ผู้โจมตีก็ไม่สามารถอ่านเนื้อหาได้ EncryptedSharedPreferences เป็นส่วนหนึ่งของไลบรารี AndroidX Security ซึ่งรวมถึง EncryptedFile สำหรับการเข้ารหัสไฟล์ทั้งหมด
Android SDK จัดเตรียมชุดวิธีการสำหรับทำงานกับพื้นที่เก็บข้อมูลภายในผ่านคลาส Context แต่ละวิธีส่งคืนพาธไปยังไดเรกทอรีระบบเฉพาะภายในแซนด์บ็อกซ์ของแอป มาดูการดำเนินการเขียนและอ่านไฟล์พื้นฐานโดยใช้ Kotlin เป็นตัวอย่าง
วิธีหลักในการรับพาธไปยังไดเรกทอรีไฟล์ภายในคือ context.filesDir ซึ่งส่งคืนออบเจ็กต์ File ที่ชี้ไปยังไดเรกทอรี /data/data/<package>/files/ เมื่อเข้าถึงครั้งแรก ระบบจะสร้างไดเรกทอรีหลักที่จำเป็นทั้งหมดโดยอัตโนมัติ ขนาดไฟล์ในพื้นที่เก็บข้อมูลภายในไม่ได้ถูกจำกัดอย่างชัดเจน แต่ปริมาณข้อมูลทั้งหมดต้องไม่เกินพื้นที่ว่างบนพาร์ติชัน /data ซึ่งโดยปกติจะอยู่ที่ 60–80% ของความจุหน่วยความจำแฟลชทั้งหมด
val context = getApplicationContext()
val file = File(context.filesDir, "notes.txt")
file.writeText("เนื้อหาบันทึก")
val content = file.readText()
println("อ่านแล้ว: $content")
วิธีการ writeText และ readText เป็นฟังก์ชันส่วนขยายของไลบรารีมาตรฐาน Kotlin ซึ่งจัดการการเปิดและปิดสตรีมโดยอัตโนมัติ ป้องกันการรั่วไหลของหน่วยความจำ สำหรับข้อมูลไบนารี ให้ใช้ writeBytes และ readBytes ซึ่งไม่ต้องมีการเข้ารหัสและทำงานกับอาร์เรย์ ByteArray เมื่อทำงานกับไฟล์ขนาดใหญ่ แนะนำให้ใช้สตรีมแบบบัฟเฟอร์: BufferedReader และ BufferedWriter สำหรับข้อความ BufferedInputStream และ BufferedOutputStream สำหรับข้อมูลไบนารี
เพื่อจัดระเบียบไฟล์เป็นลำดับชั้น ให้สร้างไดเรกทอรีย่อยภายใน filesDir ซึ่งช่วยจัดโครงสร้างข้อมูลตามประเภท: รูปภาพ เอกสาร ไฟล์ส่งออก วิธีการ mkdirs() จะสร้างไดเรกทอรีที่ขาดหายไปทั้งหมดในพาธ รวมถึงไดเรกทอรีที่ซ้อนกัน ตรวจสอบให้แน่ใจว่าการดำเนินการสร้างสำเร็จ — วิธีการจะส่งคืน true เฉพาะเมื่อสร้างไดเรกทอรีใหม่เท่านั้น ความล้มเหลวในการสร้างมักเกี่ยวข้องกับพื้นที่ไม่เพียงพอบนพาร์ติชัน /data หรือ inode ของระบบไฟล์หมด
val imagesDir = File(context.filesDir, "images")
if (imagesDir.mkdirs()) {
println("สร้างไดเรกทอรีแล้ว")
}
val imageFile = File(imagesDir, "photo.jpg")
imageFile.writeBytes(byteArray)
เพื่อตรวจสอบพื้นที่ว่างก่อนเขียนไฟล์ขนาดใหญ่ ให้ใช้ File.getFreeSpace() หรือ File.getUsableSpace() วิธีที่สองส่งคืนจำนวนไบต์ที่พร้อมใช้งานสำหรับแอปพลิเคชันปัจจุบันโดยพิจารณาจากโควต้าความปลอดภัย — แม่นยำกว่าในบริบทของอุปกรณ์ที่มีผู้ใช้หลายคน หากพื้นที่ว่างน้อยกว่าขนาดไฟล์ที่คาดไว้ ให้แสดงข้อความแก่ผู้ใช้และแนะนำให้เพิ่มพื้นที่ว่างในการตั้งค่าอุปกรณ์
บน iOS แอปพลิเคชันแต่ละรายการทำงานในคอนเทนเนอร์แซนด์บ็อกซ์แบบแยกส่วน ระบบไม่ได้ให้ API สำหรับออกไปนอกขอบเขตโดยไม่ได้รับสิทธิ์พิเศษ เครื่องมือหลักสำหรับทำงานกับระบบไฟล์คือคลาส FileManager จาก Foundation framework คอนเทนเนอร์แซนด์บ็อกซ์ประกอบด้วยไดเรกทอรีมาตรฐานหลายรายการ โดยแต่ละรายการมีนโยบายสำรองข้อมูลของตนเอง
ไดเรกทอรี Documents มีไว้สำหรับข้อมูลผู้ใช้ที่ควรคงอยู่ระหว่างการเปิดใช้แอปพลิเคชันและกู้คืนจากการสำรองข้อมูล iOS จะรวมไดเรกทอรีนี้ในการสำรองข้อมูล iCloud และ iTunes โดยอัตโนมัติ วิธีการ urls(for:in:) ส่งคืนอาร์เรย์ของ URL ของไดเรกทอรีที่ร้องขอ — องค์ประกอบแรกของอาร์เรย์เป็นหลัก
let fm = FileManager.default
let docs = fm.urls(
for: .documentDirectory,
in: .userDomainMask
).first!
let fileURL = docs.appendingPathComponent("data.plist")
try data.write(to: fileURL)
FileManager รองรับชุดการดำเนินการไฟล์อย่างสมบูรณ์: การสร้าง คัดลอก ย้าย ลบ และเปลี่ยนชื่อไฟล์ แต่ละการดำเนินการสามารถโยนข้อผิดพลาดได้ ดังนั้นการเรียกทั้งหมดต้องห่อด้วยโครงสร้าง do-catch ให้ความสนใจเป็นพิเศษกับการลบไฟล์ — การดำเนินการไม่สามารถย้อนกลับได้และการกู้คืนข้อมูลหลังจาก removeItem(at:) เป็นไปไม่ได้หากไม่มีการสำรองข้อมูลก่อน
ไม่ใช่ข้อมูลทั้งหมดในคอนเทนเนอร์แซนด์บ็อกซ์ควรรวมอยู่ในการสำรองข้อมูล iCloud ตัวอย่างเช่น รูปภาพที่ดาวน์โหลดในแคชหรือไฟล์ประมวลผลชั่วคราวไม่จำเป็นต้องกู้คืน — ไฟล์เหล่านั้นจะถูกสร้างขึ้นใหม่เมื่อใช้งานครั้งต่อไป หากต้องการแยกไดเรกทอรีหรือไฟล์ออกจากการสำรองข้อมูล ให้ตั้งค่าแอตทริบิวต์ isExcludedFromBackup เป็น true Apple แนะนำให้แยกข้อมูลที่สามารถกู้คืนจากระยะไกลออกจากการสำรองข้อมูลเสมอ เพื่อลดการใช้พื้นที่เก็บข้อมูล iCloud และลดเวลาในการกู้คืน
var cacheURL = fm.urls(
for: .cachesDirectory,
in: .userDomainMask
).first!
cacheURL.hasExcludedFromBackupKey = true
var values = URLResourceValues()
values.isExcludedFromBackup = true
try cacheURL.setResourceValues(values)
พื้นที่เก็บข้อมูลแต่ละประเภทบนอุปกรณ์มือถือมีวัตถุประสงค์และกฎการใช้งานของตนเอง การทำความเข้าใจความแตกต่างเหล่านี้ช่วยให้นักพัฒนาเลือกตำแหน่งที่เหมาะสมสำหรับข้อมูลแต่ละประเภท ด้านล่างนี้คือการเปรียบเทียบพื้นที่เก็บข้อมูลหลักสามประเภทที่พร้อมใช้งานสำหรับแอปพลิเคชัน
| คุณลักษณะ | Internal Storage | ไดเรกทอรีแคช | External Storage |
|---|---|---|---|
| การมองเห็นสำหรับแอปอื่น | ซ่อน | ซ่อน | เข้าถึงได้ |
| การลบเมื่อถอนการติดตั้งแอป | สมบูรณ์ | สมบูรณ์ | ขึ้นอยู่กับตำแหน่ง |
| การสำรองข้อมูล | Android — ไม่, iOS — ใช่ (Documents) | ไม่ | เฉพาะเมื่อซิงค์ |
| ความพร้อมใช้งานโดยไม่มีสื่อ | เสมอ | เสมอ | ต้องการการ์ด SD |
| ความเสี่ยงในการสูญเสียข้อมูล | น้อยที่สุด | สูง | ปานกลาง |
| ขนาดไฟล์ที่แนะนำ | สูงสุด 100 MB | สูงสุด 50 MB | ใดก็ได้ |
พื้นที่เก็บข้อมูลภายในเหมาะสำหรับการจัดเก็บการกำหนดค่าแอป ไฟล์ฐานข้อมูล และเอกสารผู้ใช้ที่ไม่ควรเข้าถึงได้โดยโปรแกรมอื่น ไดเรกทอรีแคชมีไว้สำหรับไฟล์ชั่วคราวที่สามารถสร้างขึ้นใหม่เมื่อใช้งานครั้งต่อไป: รูปภาพที่ดาวน์โหลด การตอบสนอง API ข้อมูลประมวลผลระหว่างกลาง พื้นที่เก็บข้อมูลภายนอกเหมาะสมที่สุดสำหรับไฟล์สื่อขนาดใหญ่ (ภาพถ่าย วิดีโอ เพลง) และข้อมูลที่ผู้ใช้ต้องการแชร์กับแอปพลิเคชันอื่นผ่านการเข้าถึงแบบใช้ร่วมกัน
การเลือกประเภทพื้นที่เก็บข้อมูลยังส่งผลต่อคะแนนของแอปใน Google Play และ App Store แอปพลิเคชันที่จัดเก็บข้อมูลปริมาณมากในพื้นที่เก็บข้อมูลภายในโดยไม่ทำความสะอาดได้รับรีวิวเชิงลบ: ผู้ใช้บ่นเกี่ยวกับพื้นที่ไม่เพียงพอ ตามการศึกษาของ App Annie ผู้ใช้ 62% ลบแอปหากใช้พื้นที่เก็บข้อมูลภายในของอุปกรณ์มากกว่า 500 MB โดยไม่มีตัวเลือกในการทำความสะอาด
การจัดการที่เหมาะสมของพื้นที่เก็บข้อมูลภายในของแอปช่วยปรับปรุงประสิทธิภาพ ความปลอดภัย และประสบการณ์ผู้ใช้ คำแนะนำต่อไปนี้อิงจากเอกสารทางการของ Android และ iOS รวมถึงประสบการณ์จริงในการพัฒนาแอปพลิเคชันที่มีการติดตั้งนับล้านครั้ง
ควรให้ความสนใจเป็นพิเศษกับการทดสอบกรณีขอบ ตรวจสอบพฤติกรรมของแอปพลิเคชันเมื่อพื้นที่เก็บข้อมูลภายในเต็ม เมื่อการดำเนินการเขียนถูกขัดจังหวะโดยไม่คาดคิด (แอปหยุดทำงาน สายเรียกเข้า) และเมื่อกู้คืนจากการสำรองข้อมูล iOS ในแต่ละสถานการณ์เหล่านี้ ข้อมูลต้องคงความสอดคล้องหรือกู้คืนไปยังสถานะเสถียรล่าสุด ใช้ไฟล์แบบธุรกรรม: เขียนข้อมูลลงในไฟล์ชั่วคราว จากนั้นเปลี่ยนชื่อเป็นเป้าหมายแบบอะตอมมิก ซึ่งป้องกันการอ่านข้อมูลที่เสียหายเมื่อการเขียนล้มเหลว
อย่าลืมการควบคุมของผู้ใช้ จัดเตรียมตัวเลือกในการล้างข้อมูลชั่วคราวและแสดงปริมาณพื้นที่เก็บข้อมูลภายในที่ใช้ในการตั้งค่าแอป ตาม Google Play Console แอปที่มีคุณสมบัตินี้ได้รับรีวิวเชิงบวกมากกว่า 18% ในหมวดหมู่ “ประสิทธิภาพ”
คำถามที่พบบ่อย
ข้อมูลทั้งหมดจากพื้นที่เก็บข้อมูลภายในของแอปจะถูกลบอย่างสมบูรณ์ ระบบปฏิบัติการรับประกันว่าไม่มีไฟล์หลงเหลือ รวมถึงฐานข้อมูล การตั้งค่า และไฟล์ชั่วคราว ข้อมูลบนพื้นที่เก็บข้อมูลภายนอกอาจยังคงอยู่
หากไม่มีสิทธิ์เข้าถึงรูทในอุปกรณ์ แอปอื่นไม่สามารถอ่านไฟล์จาก Internal Storage ของแอปอื่นได้ บน Android ต้องใช้สิทธิ์ผู้ดูแลระบบ ในขณะที่บน iOS การแยกส่วนจะถูกบังคับใช้ที่ระดับเคอร์เนลผ่านแซนด์บ็อกซ์
ไม่มีข้อจำกัดที่ชัดเจน แต่ปริมาณรวมถูกจำกัดโดยพื้นที่ว่างบนพาร์ติชัน /data แนะนำไม่ให้เกิน 100 MB ต่อแอปพลิเคชัน — ปริมาณที่ใหญ่กว่าควรวางในพื้นที่เก็บข้อมูลภายนอกหรือคลาวด์
filesDir มีไว้สำหรับข้อมูลถาวรของแอปและระบบจะไม่ลบยกเวณจำเป็น cacheDir สำหรับไฟล์ชั่วคราวที่ระบบอาจลบเมื่อหน่วยความจำต่ำ ระบบไม่รับประกันความคงทนของ cacheDir
การคัดลอกโดยตรงจากInternal Storageไปยังการ์ด SD ถูกห้ามโดยนโยบายความปลอดภัย ใช้ MediaStore API บน Android 10+ หรือ SAF (Storage Access Framework) เพื่อสร้างสำเนาข้อมูลในพื้นที่เก็บข้อมูลที่ใช้ร่วมกันโดยได้รับความยินยอมจากผู้ใช้
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม