Praktik terbaik untuk menulis ke file

API penting

Pengembang terkadang mengalami serangkaian masalah umum saat menggunakan metode Tulis kelas FileIO dan PathIO untuk melakukan operasi I/O sistem file. Misalnya, masalah umum meliputi:

  • File ditulis sebagian.
  • Aplikasi menerima pengecualian saat memanggil salah satu metode.
  • Operasi meninggalkan . File TMP dengan nama file yang mirip dengan nama file target.

Metode Tulis kelas FileIO dan PathIO mencakup hal-hal berikut:

  • WriteBufferAsync
  • WriteBytesAsync
  • WriteLinesAsync
  • WriteTextAsync

Artikel ini menyediakan detail tentang cara kerja metode ini sehingga pengembang lebih memahami kapan dan bagaimana menggunakannya. Artikel ini menyediakan panduan dan tidak mencoba memberikan solusi untuk semua kemungkinan masalah I/O file.

Catatan

 Artikel ini berfokus pada metode FileIO dalam contoh dan diskusi. Namun, metode PathIO mengikuti pola yang sama dan sebagian besar panduan dalam artikel ini juga berlaku untuk metode tersebut.

Kenyamanan vs. kontrol

Objek StorageFile bukan handel file seperti model pemrograman Win32 asli. Sebaliknya, StorageFile adalah representasi file dengan metode untuk memanipulasi kontennya.

Memahami konsep ini berguna saat melakukan I/O dengan StorageFile. Misalnya, bagian Menulis ke file menyajikan tiga cara untuk menulis ke file:

Dua skenario pertama adalah yang paling umum digunakan oleh aplikasi. Menulis ke file dalam satu operasi lebih mudah dikodekan dan dikelola, dan juga menghapus tanggung jawab aplikasi agar tidak berurusan dengan banyak kompleksitas I/O file. Namun, kenyamanan ini dikenakan biaya: hilangnya kontrol atas seluruh operasi dan kemampuan untuk menangkap kesalahan pada titik-titik tertentu.

Model transaksi

Metode Tulis kelas FileIO dan PathIO membungkus langkah-langkah pada model tulis ketiga yang dijelaskan di atas, dengan lapisan tambahan. Lapisan ini dienkapsulasi dalam transaksi penyimpanan.

Untuk melindungi integritas file asli jika terjadi kesalahan saat menulis data, metode Tulis menggunakan model transaksi dengan membuka file menggunakan OpenTransactedWriteAsync. Proses ini membuat objek StorageStreamTransaction. Setelah objek transaksi ini dibuat, API menulis data dengan cara yang mirip dengan sampel Akses File atau contoh kode di artikel StorageStreamTransaction .

Diagram berikut mengilustrasikan tugas yang mendasar yang dilakukan oleh metode WriteTextAsync dalam operasi penulisan yang berhasil. Ilustrasi ini menyediakan tampilan operasi yang disederhanakan. Misalnya, ini melewati langkah-langkah seperti pengodean teks dan penyelesaian asinkron pada utas yang berbeda.

UWP API call sequence diagram for writing to a file

Keuntungan menggunakan metode Tulis kelas FileIO dan PathIO alih-alih model empat langkah yang lebih kompleks menggunakan aliran adalah:

  • Satu panggilan API untuk menangani semua langkah perantara, termasuk kesalahan.
  • File asli disimpan jika terjadi kesalahan.
  • Status sistem akan mencoba untuk dijaga sebersih mungkin.

Namun, dengan begitu banyak kemungkinan titik kegagalan perantara, ada kemungkinan kegagalan yang meningkat. Ketika kesalahan terjadi, mungkin sulit untuk memahami di mana proses gagal. Bagian berikut menyajikan beberapa kegagalan yang mungkin Anda temui saat menggunakan metode Tulis dan memberikan solusi yang mungkin.

Kode kesalahan umum untuk metode Tulis kelas FileIO dan PathIO

Tabel ini menyajikan kode kesalahan umum yang ditemui pengembang aplikasi saat menggunakan metode Tulis . Langkah-langkah dalam tabel sesuai dengan langkah-langkah dalam diagram sebelumnya.

Nama kesalahan (nilai) Langkah-langkah Penyebab Solusi
ERROR_ACCESS_DENIED (0X80070005) 5 File asli mungkin ditandai untuk dihapus, mungkin dari operasi sebelumnya. Coba lagi operasi.
Pastikan akses ke file disinkronkan.
ERROR_SHARING_VIOLATION (0x80070020) 5 File asli dibuka oleh tulisan eksklusif lainnya. Coba lagi operasi.
Pastikan akses ke file disinkronkan.
ERROR_UNABLE_TO_REMOVE_REPLACED (0x80070497) 19-20 File asli (file.txt) tidak dapat diganti karena sedang digunakan. Proses atau operasi lain mendapatkan akses ke file sebelum dapat diganti. Coba lagi operasi.
Pastikan akses ke file disinkronkan.
ERROR_DISK_FULL (0x80070070) 7, 14, 16, 20 Model yang ditransaksikan membuat file tambahan, dan ini mengonsumsi penyimpanan tambahan.
ERROR_OUTOFMEMORY (0x8007000E) 14, 16 Ini dapat terjadi karena beberapa operasi I/O yang luar biasa atau ukuran file besar. Pendekatan yang lebih terperinci dengan mengontrol aliran dapat mengatasi kesalahan.
E_FAIL (0x80004005) Mana pun Lain-lain Coba lagi operasi. Jika masih gagal, mungkin kesalahan platform dan aplikasi harus dihentikan karena dalam keadaan tidak konsisten.

Pertimbangan lain untuk status file yang mungkin menyebabkan kesalahan

Selain kesalahan yang dikembalikan oleh metode Tulis , berikut adalah beberapa panduan tentang apa yang dapat diharapkan aplikasi saat menulis ke file.

Data ditulis ke file jika dan hanya jika operasi selesai

Aplikasi Anda tidak boleh membuat asumsi tentang data dalam file saat operasi tulis sedang berlangsung. Mencoba mengakses file sebelum operasi selesai dapat menyebabkan data yang tidak konsisten. Aplikasi Anda harus bertanggung jawab untuk melacak I/Os yang luar biasa.

Pembaca

Jika file yang ditulis juga digunakan oleh pembaca yang sopan (yaitu, dibuka dengan FileAccessMode.Read, bacaan berikutnya akan gagal dengan kesalahan ERROR_OPLOCK_HANDLE_CLOSED (0x80070323). Terkadang aplikasi mencoba kembali membuka file untuk dibaca lagi saat operasi Tulis sedang berlangsung. Ini dapat mengakibatkan kondisi balapan di mana Write akhirnya gagal ketika mencoba menimpa file asli karena tidak dapat diganti.

File dari KnownFolders

Aplikasi Anda mungkin bukan satu-satunya aplikasi yang mencoba mengakses file yang berada di salah satu KnownFolders. Tidak ada jaminan bahwa jika operasi berhasil, konten yang ditulis aplikasi ke file akan tetap konstan saat berikutnya mencoba membaca file. Selain itu, kesalahan berbagi atau akses yang ditolak menjadi lebih umum dalam skenario ini.

I/O yang Bertentangan

Kemungkinan kesalahan konkurensi dapat diturunkan jika aplikasi kami menggunakan metode Tulis untuk file dalam data lokalnya, tetapi beberapa perhatian masih diperlukan. Jika beberapa operasi Tulis dikirim secara bersamaan ke file, tidak ada jaminan tentang data apa yang berakhir dalam file. Untuk mengurangi hal ini, kami sarankan aplikasi Anda menserialisasikan operasi Tulis ke file.

~File TMP

Terkadang, jika operasi dibatalkan secara paksa (misalnya, jika aplikasi ditangguhkan atau dihentikan oleh OS), transaksi tidak dilakukan atau ditutup dengan tepat. Ini dapat meninggalkan file dengan ekstensi (.~TMP). Pertimbangkan untuk menghapus file sementara ini (jika ada di data lokal aplikasi) saat menangani aktivasi aplikasi.

Pertimbangan berdasarkan jenis file

Beberapa kesalahan dapat menjadi lebih umum tergantung pada jenis file, frekuensi aksesnya, dan ukuran filenya. Umumnya, ada tiga kategori file yang dapat diakses aplikasi Anda:

  • File yang dibuat dan diedit oleh pengguna di folder data lokal aplikasi Anda. Ini dibuat dan diedit hanya saat menggunakan aplikasi Anda, dan hanya ada di dalam aplikasi.
  • Metadata aplikasi. Aplikasi Anda menggunakan file-file ini untuk melacak statusnya sendiri.
  • File lain di lokasi sistem file tempat aplikasi Anda mendeklarasikan kemampuan untuk diakses. Ini paling umum terletak di salah satu KnownFolder.

Aplikasi Anda memiliki kontrol penuh pada dua kategori file pertama, karena merupakan bagian dari file paket aplikasi Anda dan diakses oleh aplikasi Anda secara eksklusif. Untuk file dalam kategori terakhir, aplikasi Anda harus mengetahui bahwa aplikasi dan layanan OS lain mungkin mengakses file secara bersamaan.

Bergantung pada aplikasi, akses ke file dapat bervariasi pada frekuensi:

  • Sangat rendah. Ini biasanya adalah file yang dibuka sekali ketika aplikasi diluncurkan dan disimpan saat aplikasi ditangguhkan.
  • Rendah. Ini adalah file yang secara khusus dilakukan oleh pengguna untuk mengambil tindakan (seperti menyimpan atau memuat).
  • Sedang atau tinggi. Ini adalah file di mana aplikasi harus terus memperbarui data (misalnya, fitur penyimpanan otomatis atau pelacakan metadata konstan).

Untuk ukuran file, pertimbangkan data performa dalam bagan berikut untuk metode WriteBytesAsync . Bagan ini membandingkan waktu untuk menyelesaikan operasi vs ukuran file, lebih dari performa rata-rata 10000 operasi per ukuran file di lingkungan terkontrol.

WriteBytesAsync performance

Nilai waktu pada sumbu y dihilangkan dengan sengaja dari bagan ini karena perangkat keras dan konfigurasi yang berbeda akan menghasilkan nilai waktu absolut yang berbeda. Namun, kami telah secara konsisten mengamati tren ini dalam pengujian kami:

  • Untuk file yang sangat kecil (<= 1 MB): Waktu untuk menyelesaikan operasi secara konsisten cepat.
  • Untuk file yang lebih besar (> 1 MB): Waktu untuk menyelesaikan operasi mulai meningkat secara eksponensial.

I/O selama penangguhan aplikasi

Aplikasi Anda harus dirancang untuk menangani penangguhan jika Anda ingin menyimpan informasi status atau metadata untuk digunakan dalam sesi selanjutnya. Untuk informasi latar belakang tentang penangguhan aplikasi, lihat Siklus hidup aplikasi dan posting blog ini.

Kecuali OS memberikan eksekusi yang diperluas ke aplikasi Anda, saat aplikasi Anda ditangguhkan, OS memiliki waktu 5 detik untuk merilis semua sumber dayanya dan menyimpan datanya. Untuk keandalan terbaik dan pengalaman pengguna, selalu asumsikan waktu Yang Anda miliki untuk menangani tugas penangguhan terbatas. Perlu diingat panduan berikut selama periode waktu 5 detik untuk menangani tugas penangguhan:

  • Cobalah untuk menjaga I/O tetap minimal untuk menghindari kondisi balapan yang disebabkan oleh operasi pembilasan dan pelepasan.
  • Hindari menulis file yang memerlukan ratusan milidetik atau lebih untuk menulis.
  • Jika aplikasi Anda menggunakan metode Tulis , ingatlah semua langkah perantara yang diperlukan metode ini.

Jika aplikasi Anda beroperasi pada sejumlah kecil data status selama penangguhan, dalam banyak kasus Anda dapat menggunakan metode Tulis untuk menghapus data. Namun, jika aplikasi Anda menggunakan sejumlah besar data status, pertimbangkan untuk menggunakan aliran untuk menyimpan data Anda secara langsung. Ini dapat membantu mengurangi penundaan yang diperkenalkan oleh model transaksional metode Tulis .

Misalnya, lihat sampel BasicSuspension .

Contoh dan sumber daya lainnya

Berikut adalah beberapa contoh dan sumber daya lainnya untuk skenario tertentu.

Contoh kode untuk mencoba kembali contoh I/O file

Berikut ini adalah contoh pseudo-code tentang cara mencoba kembali tulis (C#), dengan asumsi penulisan akan dilakukan setelah pengguna memilih file untuk disimpan:

Windows.Storage.Pickers.FileSavePicker savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();

Int32 retryAttempts = 5;

const Int32 ERROR_ACCESS_DENIED = unchecked((Int32)0x80070005);
const Int32 ERROR_SHARING_VIOLATION = unchecked((Int32)0x80070020);

if (file != null)
{
    // Application now has read/write access to the picked file.
    while (retryAttempts > 0)
    {
        try
        {
            retryAttempts--;
            await Windows.Storage.FileIO.WriteTextAsync(file, "Text to write to file");
            break;
        }
        catch (Exception ex) when ((ex.HResult == ERROR_ACCESS_DENIED) ||
                                   (ex.HResult == ERROR_SHARING_VIOLATION))
        {
            // This might be recovered by retrying, otherwise let the exception be raised.
            // The app can decide to wait before retrying.
        }
    }
}
else
{
    // The operation was cancelled in the picker dialog.
}

Menyinkronkan akses ke file

Blog Pemrograman Paralel dengan .NET adalah sumber daya yang bagus untuk panduan tentang pemrograman paralel. Secara khusus, postingan tentang AsyncReaderWriterLock menjelaskan cara mempertahankan akses eksklusif ke file untuk ditulis sambil memungkinkan akses baca bersamaan. Perlu diingat bahwa serialisasi I/O akan berdampak pada performa.

Baca juga