Apa cara yang tepat untuk menangani file teks besar di Objective-C? Katakanlah saya perlu membaca setiap baris secara terpisah dan ingin memperlakukan setiap baris sebagai NSString. Apa cara paling efisien untuk melakukan ini?
Salah satu solusinya adalah menggunakan metode NSString:
+ (id)stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc
error:(NSError **)error
dan kemudian membaginya dengan pemisah baris baru, dan kemudian iterate atas elemen dalam array. Namun, ini tampaknya tidak efisien. Apakah tidak ada cara mudah untuk memperlakukan file sebagai stream, menghitung setiap baris, alih-alih hanya membacanya sekaligus? Agak seperti java.io.BufferedReader Java.
Jawaban:
Itu pertanyaan yang bagus. Saya pikir @Diederik memiliki jawaban yang bagus, meskipun sangat disayangkan bahwa Kakao tidak memiliki mekanisme untuk apa yang ingin Anda lakukan.
NSInputStream
memungkinkan Anda membaca potongan N byte (sangat mirip denganjava.io.BufferedReader
), tetapi Anda harus mengonversinya menjadiNSString
Anda sendiri, kemudian memindai baris baru (atau pembatas lainnya) dan menyimpan karakter yang tersisa untuk dibaca selanjutnya, atau membaca lebih banyak karakter jika baris baru belum dibaca. (NSFileHandle
memungkinkan Anda membacaNSData
yang kemudian dapat dikonversi menjadiNSString
, tetapi pada dasarnya prosesnya sama.)Apple memiliki Panduan Pemrograman Stream yang dapat membantu mengisi detail, dan pertanyaan SO ini dapat membantu juga jika Anda akan berurusan dengan
uint8_t*
buffer.Jika Anda akan sering membaca string seperti ini (terutama di berbagai bagian program Anda) adalah ide yang baik untuk merangkum perilaku ini di kelas yang dapat menangani detail untuk Anda, atau bahkan subklasifikasi
NSInputStream
(ini dirancang untuk menjadi subclass ) dan menambahkan metode yang memungkinkan Anda untuk membaca apa yang Anda inginkan.Sebagai catatan, saya pikir ini akan menjadi fitur yang bagus untuk ditambahkan, dan saya akan mengajukan permintaan tambahan untuk sesuatu yang memungkinkan ini terjadi. :-)
Sunting: Ternyata permintaan ini sudah ada. Ada Radar yang berasal dari tahun 2006 untuk ini (rdar: // 4742914 untuk orang-orang internal Apple).
sumber
Ini akan berfungsi untuk membaca secara umum
String
dariText
. Jika Anda ingin membaca teks yang lebih panjang ( teks berukuran besar) , maka gunakan metode yang disebut orang lain di sini seperti buffered (cadangan ukuran teks dalam ruang memori) .Katakanlah Anda membaca File Teks.
Anda ingin menyingkirkan baris baru.
Itu dia.
sumber
Ini harus melakukan trik:
Gunakan sebagai berikut:
Kode ini membaca karakter non-baris baru dari file, hingga 4095 sekaligus. Jika Anda memiliki garis yang lebih panjang dari 4095 karakter, ia terus membaca hingga mencapai baris baru atau akhir file.
Catatan : Saya belum menguji kode ini. Silakan mengujinya sebelum menggunakannya.
sumber
"%4095[^\n]%n%*c"
diam-diam akan mengkonsumsi dan membuang satu karakter dengan masing-masing buffer membaca. Sepertinya format ini mengasumsikan bahwa garis akan lebih pendek dari panjang buffer.Mac OS X adalah Unix, Objective-C adalah superset C, jadi Anda bisa menggunakan old-school
fopen
danfgets
dari<stdio.h>
. Dijamin bekerja.[NSString stringWithUTF8String:buf]
akan mengonversi string C menjadiNSString
. Ada juga metode untuk membuat string dalam pengkodean lain dan membuat tanpa menyalin.sumber
fgets
akan menyertakan'\n'
karakter, jadi Anda mungkin ingin menghapusnya sebelum mengonversi string.Anda dapat menggunakan
NSInputStream
yang memiliki implementasi dasar untuk aliran file. Anda dapat membaca byte ke buffer (read:maxLength:
metode). Anda harus memindai sendiri buffer untuk baris baru.sumber
Cara yang tepat untuk membaca file teks dalam Cocoa / Objective-C didokumentasikan dalam panduan pemrograman String Apple. Bagian untuk membaca dan menulis file harus sesuai keinginan Anda. PS: Apa itu "garis"? Dua bagian string yang dipisahkan oleh "\ n"? Atau "\ r"? Atau "\ r \ n"? Atau mungkin Anda benar-benar setelah paragraf? Panduan yang disebutkan sebelumnya juga termasuk bagian tentang pemisahan string menjadi garis atau paragraf. (Bagian ini disebut "Paragraph dan Line Breaks", dan terhubung dengan di menu sebelah kiri dari halaman yang saya tunjukkan di atas. Sayangnya situs ini tidak memungkinkan saya untuk mengirim lebih dari satu URL karena saya belum menjadi pengguna yang dapat dipercaya.)
Mengutip Knuth: optimisasi prematur adalah akar dari semua kejahatan. Jangan hanya berasumsi bahwa "membaca seluruh file ke dalam memori" lambat. Sudahkah Anda membandingkannya? Apakah Anda tahu itu benar - benar membaca seluruh file ke dalam memori? Mungkin itu hanya mengembalikan objek proxy dan terus membaca di belakang layar saat Anda mengkonsumsi string? ( Penafian: Saya tidak tahu apakah NSString benar-benar melakukan ini. Bisa dibayangkan. ) Intinya adalah: pertama-tama lakukanlah dengan cara terdokumentasi dalam melakukan sesuatu. Kemudian, jika tolok ukur menunjukkan bahwa ini tidak memiliki kinerja yang Anda inginkan, optimalkan.
sumber
-stringWithContentsOf*
metode yang diikuti oleh-componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]
, itu akan melihat\r
dan\n
secara terpisah dan menambahkan baris kosong setelah setiap baris.Banyak dari jawaban ini adalah potongan kode yang panjang atau mereka baca di seluruh file. Saya suka menggunakan metode c untuk tugas ini.
Perhatikan bahwa fgetln tidak akan menyimpan karakter baris baru Anda. Juga, Kami memberi +1 panjang str karena kami ingin memberikan ruang untuk penghentian NULL.
sumber
Untuk membaca file baris demi baris (juga untuk file besar yang ekstrem) dapat dilakukan dengan fungsi-fungsi berikut:
Atau:
Kelas DDFileReader yang memungkinkan ini adalah sebagai berikut:
File Antarmuka (.h):
Implementasi (.m)
Kelas dilakukan oleh Dave DeLong
sumber
Seperti yang dikatakan @porneL, api C sangat berguna.
sumber
Seperti yang lain telah menjawab baik NSInputStream dan NSFileHandle adalah opsi yang baik, tetapi juga dapat dilakukan dengan cara yang cukup kompak dengan NSData dan pemetaan memori:
BRLineReader.h
BRLineReader.m
sumber
Jawaban ini BUKAN ObjC tetapi C.
Karena ObjC berbasis 'C', mengapa tidak menggunakan fgets?
Dan ya, saya yakin ObjC memiliki metode sendiri - Saya belum cukup mahir untuk mengetahui apa itu :)
sumber
meta
pertanyaan; haruskah pertanyaan yang sangat lama dari pengguna biasa dapat ditandai untuk ditinjau?dari jawaban @Adam Rosenfield, string pemformatan
fscanf
akan diubah seperti di bawah ini:ini akan bekerja di osx, linux, ujung baris windows.
sumber
Menggunakan kategori atau ekstensi untuk membuat hidup kita sedikit lebih mudah.
sumber
Saya menemukan respons oleh @lukaswelte dan kode dari Dave DeLong sangat membantu. Saya sedang mencari solusi untuk masalah ini tetapi perlu mengurai file besar dengan
\r\n
tidak hanya\n
.Kode seperti tertulis berisi bug jika parsing oleh lebih dari satu karakter. Saya telah mengubah kode seperti di bawah ini.
file .h:
file .m:
sumber
Saya menambahkan ini karena semua jawaban lain yang saya coba gagal. Metode berikut ini dapat menangani file besar, garis panjang sembarang, serta baris kosong. Ini telah diuji dengan konten aktual dan akan menghapus karakter baris baru dari output.
Kredit jatuh ke @Adam Rosenfield dan @sooop
sumber
Saya melihat banyak jawaban ini bergantung pada membaca seluruh file teks ke dalam memori daripada mengambilnya satu per satu. Inilah solusi saya di Swift modern yang bagus, menggunakan FileHandle untuk menjaga dampak memori rendah:
Perhatikan bahwa ini menjaga carriage return di akhir baris, jadi tergantung pada kebutuhan Anda, Anda mungkin ingin menyesuaikan kode untuk menghapusnya.
Penggunaan: cukup buka pegangan file ke file teks target Anda dan panggil
readLine
dengan panjang maksimum yang sesuai - 1024 adalah standar untuk teks biasa, tetapi saya membiarkannya terbuka jika Anda tahu itu akan lebih pendek. Perhatikan bahwa perintah tidak akan meluap akhir file, jadi Anda mungkin harus memeriksa secara manual bahwa Anda belum mencapainya jika Anda bermaksud menguraikan semuanya. Berikut ini beberapa contoh kode yang menunjukkan cara membuka file dimyFileURL
dan membacanya baris demi baris hingga akhir.sumber
Inilah solusi sederhana yang bagus yang saya gunakan untuk file yang lebih kecil:
sumber
Gunakan skrip ini, ini berfungsi dengan baik:
sumber