@@ -210,8 +210,185 @@ Buraya kadar ele aldığımız stdin ve stdout kullanımlarına ilişkin şunlar
210
210
- ** Unix/Linux** ortamlarında ` | ` , ` > ` ve ` >> ` operatörleri standart giriş-çıkış işlemlerinde, verilerin akışını
211
211
yönetmek için kullanılır.
212
212
213
+ ---
214
+
213
215
## Temel Dosya I/O İşlemleri
214
216
215
217
Aşağıdaki örneklerde dosya okuma ve yazma işlemleri farklı şekillerde ele alınmaktadır.
216
218
217
- _ NotYetImplemented();_
219
+ ### Dosya Oluşturma ve İçerik Yazma _ (create)_
220
+
221
+ Aşağıdaki fonksiyon parametre olarak Game türünden bir dizi alır. Bu dizinin her bir elemanı için satır satır akan bir
222
+ String içerik üretilir. Söz konusu içerik contents isimli değişkende toplanır. f değişkeni games.dat isimli bir dosyayı
223
+ temsil eder. Dosya create metodu ile oluşturulur. Create metodu dosya yoksa yeni bir tane oluşturur ama varsa truncate
224
+ işlemini icra eder, bir başka deyişle içeriğini sıfırlar.
225
+
226
+ ``` rust
227
+ pub fn write_games_to_file (games : & [Game ]) -> io :: Result <()> {
228
+ let mut contents = String :: new ();
229
+ for g in games {
230
+ contents . push_str (& g . to_string ());
231
+ contents . push_str (" \ n" );
232
+ }
233
+ let mut f = File :: create (" games.dat" )? ;
234
+ f . write_all (contents . as_bytes ())? ;
235
+ Ok (())
236
+ }
237
+ ```
238
+
239
+ ### Dosya İçeriğini Okuma
240
+
241
+ Aşağıdaki örnek kod ** games.dat** isimli dosyanın içeriğini satır satır okuyarak ** String** türünden bir vector'de
242
+ toplar. Burada satır bazında okuma işlemi yapmak için ** BufReader** nesnesi kullanılmıştır. ** BufReader** esasında bu
243
+ örnek için oldukça maliyetlidir. Genel olarak ** TCP Stream** 'lerin okunması gibi işlemlerde ** BufReader** kullanmak daha
244
+ mantıklıdır.
245
+
246
+ ``` rust
247
+ pub fn read_games_from_file () -> io :: Result <Vec <String >> {
248
+ let mut games = Vec :: new ();
249
+ let f = File :: open (" games.dat" )? ;
250
+ for line in BufReader :: new (f ). lines () {
251
+ games . push (line ? );
252
+ }
253
+ Ok (games )
254
+ }
255
+ ```
256
+
257
+ Yukarıdaki fonksiyondan yararlanılarak dosya içerisinde yer alan oyun bilgilerinin ** |** işaretine göre ayrıştırılıp
258
+ ** Game** türünden bir ** vector** halinde ele alınması da mümkündür. Bunun için aşağıdaki gibi bir fonksiyondan
259
+ yararlanılabilir.
260
+
261
+ ``` rust
262
+ pub fn read_games_to_vec () -> io :: Result <Vec <Game >> {
263
+ let mut games = Vec :: new ();
264
+
265
+ for line in read_games_from_file ()? {
266
+ let cols : Vec <& str > = line . split ('|' ). collect ();
267
+ if cols . len () != 3 {
268
+ return Err (io :: Error :: new (
269
+ io :: ErrorKind :: InvalidData ,
270
+ format! (" Beklenmeyen sütun sayısı: `{}`" , line ),
271
+ ));
272
+ }
273
+
274
+ let title = cols [0 ]. to_string ();
275
+ let year = cols [1 ]
276
+ . parse :: <u16 >()
277
+ . map_err (| e | io :: Error :: new (io :: ErrorKind :: InvalidData , e ))? ;
278
+ let popularity = cols [2 ]
279
+ . parse :: <f32 >()
280
+ . map_err (| e | io :: Error :: new (io :: ErrorKind :: InvalidData , e ))? ;
281
+
282
+ games . push (Game {
283
+ title ,
284
+ year ,
285
+ popularity ,
286
+ });
287
+ }
288
+
289
+ Ok (games )
290
+ }
291
+ ```
292
+
293
+ Yukarıdaki iki operasyon tek bir metot haline de getirilebilir. İlk olarak path parametresi üzerinden gelen dosya
294
+ açılmaya çalışılır. Operasyon sonrasında hata olması durumu söz konusudur ve bu ** ?** operatörü ile ele alınarak ** error
295
+ propagation** ile çağıran yere doğru gönderilir. Dosya içeriğini satır bazından okumak için ** BufReader** nesnesi
296
+ kullanılır. Bu nesne oluşturulurken bir file nesnesi aldığına dikkat edilmelidir. ** BufReader** üzerinden ulaşılan lines
297
+ metodu satır bazında okuma yapılmasını sağlar. Döngünün her iterasyonunda dosyadan bir satır okunur. Bu işlem okunabilir
298
+ satır kalmayıncaya kadar devam eder. İlgili kontrol is_empty çağrısı ile gerçekleştirilmektedir. Game nesnesnin dosya
299
+ içerisindeki tutuluş biçimine göre ** |** işaretleri ile ayrılmış 3 kolon olması gerekmektedir. Bu durum kontrol edilir
300
+ ve hatalı kolon olması halinde geriye bir Error döndürülür. Buradaki akış tamamen stratejiye bağlıdır. Hatalı kolonların
301
+ olduğu satırları atlayarak devam etmek de bir seçenektir.
302
+
303
+ Kolonlar elde edilikten sonra bazı dönüştürme işlemleri de icra edilir ve bunlarda da ** error propagation** tekniği
304
+ kullanılır.
305
+
306
+ ``` rust
307
+ pub fn read_games_buffered_into_vec (path : & str ) -> io :: Result <Vec <Game >> {
308
+ let file = File :: open (path )? ;
309
+ let reader = BufReader :: new (file );
310
+ let mut games = Vec :: new ();
311
+ for line in reader . lines () {
312
+ let line = line ? ;
313
+ if ! line . is_empty () {
314
+ let cols : Vec <& str > = line . split ('|' ). collect ();
315
+ if cols . len () != 3 {
316
+ return Err (io :: Error :: new (
317
+ io :: ErrorKind :: InvalidData ,
318
+ format! (" Beklenmeyen sütun sayısı: `{}`" , line ),
319
+ ));
320
+ }
321
+ let title = cols [0 ]. to_string ();
322
+ let year = cols [1 ]
323
+ . parse :: <u16 >()
324
+ . map_err (| e | io :: Error :: new (io :: ErrorKind :: InvalidData , e ))? ;
325
+ let popularity = cols [2 ]
326
+ . parse :: <f32 >()
327
+ . map_err (| e | io :: Error :: new (io :: ErrorKind :: InvalidData , e ))? ;
328
+
329
+ games . push (Game {
330
+ title ,
331
+ year ,
332
+ popularity ,
333
+ });
334
+ }
335
+ }
336
+ Ok (games )
337
+ }
338
+ ```
339
+
340
+ ### Dosyaya Veri Yazma
341
+
342
+ Bir dosyaya veri yazma işlemi aslında içeriğin bir byte array olarak aktarılmasından ibarettir. Aşağıdaki örnek
343
+ fonksiyonu ele alalım.
344
+
345
+ ``` rust
346
+ pub fn write_games_to_file (games : & [Game ]) -> io :: Result <()> {
347
+ let mut contents = String :: new ();
348
+ for g in games {
349
+ contents . push_str (& g . to_string ());
350
+ contents . push_str (" \ n" );
351
+ }
352
+ let mut f = File :: create (" games.dat" )? ;
353
+ f . write_all (contents . as_bytes ())? ;
354
+ Ok (())
355
+ }
356
+ ```
357
+
358
+ Bu fonksiyon Game nesnelerinden oluşan bir diziyi parametre olarak alır. Her bir oyun değişkeni için içeriği | ile
359
+ ayıran bir string üretilir ve bunlar contents isimli String değişkende toplanır. Satır bazında ayrıştırılarak tutulan
360
+ içerik as_bytes metodu ile byte array'a çevrilip tek seferde games.dat isimli dosyaya yazdırılır.
361
+
362
+ Yazma işlemi BufWriter enstrümanını ile de gerçekleştirilebilir. Aşağıdaki kod parçasında bu durum ele alınmaktadır. Çok
363
+ büyük blokların tek seferde yazılmasından ziyade in-memory olarak tutulan içeriklerin küçük bloklar halinde yazılması
364
+ adına daha verimlidir. Yazma operasyonu aynı kaynağa doğru ele alınır. Bir dosya veya network'e yazma en çok kullanılan
365
+ senaryolardandır. Yazma işlemi tamamlandığında bellekte kalmış olabilecek veri kalıntılarının da tamamen aktarıldığından
366
+ emin olmak gerekir. Bunun için flush komutu kullanılır.
367
+
368
+ ``` rust
369
+ pub fn write_games_buffered (path : & str , games : & [Game ]) -> io :: Result <()> {
370
+ let file = File :: create (path )? ;
371
+ let mut writer = BufWriter :: new (file );
372
+ for game in games {
373
+ writeln! (writer , " {}" , game )? ;
374
+ }
375
+ writer . flush ()? ;
376
+ Ok (())
377
+ }
378
+ ```
379
+
380
+ ### Var Olan Dosya İçeriklerine Ek Yapmak
381
+
382
+ Çoğu zaman var olan dosya içeriklerine ilaveler yapılır. Söz gelimi log biriktiren dosyalar veya oyunun son durumunu
383
+ tutan dosyalar bunlara örnek olarak verilebilir. Bu gibi senaryolarda ** OpenOptions** türünü kullanarak dosyanın hangi
384
+ modda oluşturulacağı belirtilebilir. Aşağıdaki örnekte path değişkeni üzerinden gelen dosyanın ** append** modda
385
+ açılacağı belirtilir. Buna göre dosyanın sonuna ekleme yapılacağı söylenir. Yukarıda gerçekleştirilen birçok operasyonda
386
+ doğrudan File nesnesine erişmek yerine ** OpenOptions** enstrümanı ile de ilerlenebilir.
387
+
388
+ ``` rust
389
+ pub fn append_game_to_file (path : & str , game : & Game ) -> io :: Result <()> {
390
+ let mut file = OpenOptions :: new (). append (true ). create (true ). open (path )? ;
391
+ writeln! (file , " {}" , game )? ;
392
+ Ok (())
393
+ }
394
+ ```
0 commit comments