Thread overview
File Nesnesinden Gelen Veri Nereye Yazar?
Jul 05, 2021
Salih Dincer
Jul 05, 2021
Ali Çehreli
Jul 06, 2021
Salih Dincer
Jul 06, 2021
Ali Çehreli
Jul 06, 2021
Salih Dincer
Jul 06, 2021
Salih Dincer
Jul 06, 2021
Ali Çehreli
July 05, 2021

Merhaba,

Aslında aşağıdaki kodun 2 durumu arasındaki farkın nedenini biliyorum! Ama emin olamadığım için sormalıyım; standart çıktı nereye yazar? Neden afallar, sapıtır? Eğer writeln() kullanmak istemiyorsam...

/* whereTowrite.d
 * 05.07.2021
 *
 * This is a problem?
 */

 import std.array, std.stdio;

void main (string[] ARGS)
{
  string DOSYA = "whereTowrite.d";/* [ ToggleMark ]
  if(!(ARGS.length >= 2)) {
    "LUTFEN BOYLE KULLANIN:
     whereTowrite  birmetin.txt > dfile.txt".writeln;
  } else { string DOSYA = ARGS[1];//*/
	
    auto satirlaraBol = File (DOSYA)
                       .byLineCopy
                       .array;
    uint satirSay;
    foreach(satir; satirlaraBol) {
      satir.write;
      satirSay++;
   }
   satirSay.writeln;
}
//ÇIKTISI:
//  28 satirSay.writeln;atirlaraBol) {A)ile.txt".writeln;

AÇIKLAMA: Lütfen önce bu haliyle derleyin ve satir.write'ın satır sonu karakteri görmediği için (en azından Windows'da böyle!) ekrana yazan kodlar düzgün olmayacak ama ToggleMark'ı kaparsanız altındaki kodlar (bir de en sona if'in kapamasını ekleyin) açılır ve parametre ile tam çalışan bir programınız olur. Çünkü ekrana bozuk yansıyan görüntü dosyaya doğru bir şekilde kayıt oluyor!

Başarılar...

July 05, 2021
On 7/5/21 11:31 AM, Salih Dincer wrote:

> Aslında aşağıdaki kodun 2 durumu

Ben tam anlayamadım. :(

* Sen senelerdir ToggleMark kullandığın için sana çok doğal geliyor ama biz hiç alışık olmadığımızdan anlayamıyoruz. Ben C ve C++ kodlarında `#if 0` kullanmayı biliyorum.

D'de de güzel bir olanağımız var:

```
version (none) {
  // Bu kod derlenmez çünkü 'none' hiçbir zaman tanımlı değildir
}

version (all) {
  // Bu kod derlenir çünkü 'all' her zaman tanımlıdır
}
```

Ben version'ı bu gibi durumlarda şöyle kullanıyorum:

```
version (bozuk) {
  // Buraya bozuk kodlari yerleştiriyorum

} else {
  // Buraya da diğerini
}
```

Örneğin, 'bozuk' kodlar şöyle etkinleştiriliyor:

```
version = bozuk;
```

Bunları yazmamın nedeni, ben ToggleMark konusundan hiç emin olamıyorum çünkü bu son kodda /* bölümünü //* olarak değiştirmem gerektiğini sandım ama derlenmedi. Belki ben bir yerde hata yaptım ama zor işte...

Daha önemlisi, bu kodun hangi beklentiyi karşılamadığını anlayamıyorum. Satır sonu karakteri yazılmadığı için mi yanlış.

Çıktıda 28 var. Gariplik o mu? Galiba karakterler birbirine mi girmiş?

Biraz daha basit anlatırsan sevinirim. :) Yine de anladığım kadarıyla bir şeyler yazacağım.

> standart çıktı nereye yazar?

Doğrusu, bizim programımız bunu bilemez. Programın başlangıçta dış dünyayla olan bağlantısı, kendisini başlatan ortama bir değer döndürmesi ve üç adet "akım"dır: okunan stdin, yazılan stdout ve stderr. Program kendisi File, soket vs. ile başka iletişim yolları da açabilir ama başlangıçta o kadar. "Akım" dememin nedeni de, onların gerçekten karakter akımı olmaları: karakter okunabilir ve karakter yazılabilir. Hatta bunların klavye veya ekrana bağlılıkları da kesin değildir.

Bu akımların nereye bağlı oldukları ve dönüş değerinin ne yapılacağı bizi başlatan programa kalmıştır. Çoğu durumda bu akımlar en sonunda klavyeye ve ekrana bağlıdır ve dönüş değeri "hata oldu" anlamına gelir ama öyle olmayabilir.

Ek olarak, bu akımlar performans nedeniyle ara bellek (buffer) kullanabilirler. Örneğin, program stdin'den gelen karakterleri ancak '\n' karakteri geldikten sonra görebilir veya çıkışa yazılan karakterler çoğunlukla '\n' karakteri görülene kadar bekletiliyor olabilirler.

> Neden
> afallar, sapıtır? Eğer writeln() kullanmak istemiyorsam...

writeln ile ilgili tek olay, '\n' eklemesidir. Onunla ilgili olabilir. (?)

>      auto satirlaraBol = File (DOSYA)
>                         .byLineCopy
>                         .array;

Herhalde bildiğin gibi:

* byLineCopy, bazı durumlarda gerekiyor. Başka durumlarda byLine daha hızlı olabilir çünkü satırları aynı ara belleğe okur. (O yüzden de önceki satırı elimizde tutamayız.)

* array, bütün elemanları (bu durumda "satırları") depolar. Bu da gerçekten gerekmedikçe gereksizdir.

> (bir de en sona if'in kapamasını ekleyin)

Ah! Belki de gözden kaçırdığım oydu. O yüzden ToggleMark'ı kapatınca derleyemedim galiba... Yine de, ben birbirinden bağımsız iki küçük programı daha çok severdim: "Şu istediğimi yapıyor, şu yapmıyor" gibi...

Tamam, şimdi if'i kapatan } ile deniyorum. Ama bak bu iş hiç de görüldüğü kadar kolay değil. Şöyle bir hata aldım:

Error: variable `DOSYA` is shadowing variable `whereTowrite.main.DOSYA`

Galiba ToggleMark'ı doğru kullanamadım. Satır başından kapatayım... (Görüyor musun, senin için çok doğal olan bu kullanım bizim için çok güç olabiliyor.)

Bu kadar laf kalabalığımdan sonra ben bu programı anladığım kadarıyla şöyle yazardım:

```d
import std.stdio;
import std.algorithm;
import std.range;

void main() {
  auto satırlar = stdin
                  .byLine
                  .enumerate
                  .each!(e => writefln!"%s %s"(e.index, e.value));
}
```

Yukarıda söylediğimin bir örneği olarak, standart girişi whereTowrite.d'ye şöyle bağlayabilirdim:

$ ./whereTowrite < whereTowrite.d

Ali


July 06, 2021

On Monday, 5 July 2021 at 19:28:35 UTC, Ali Çehreli wrote:

>

On 7/5/21 11:31 AM, Salih Dincer wrote:

  • Sen senelerdir ToggleMark kullandığın için sana çok doğal geliyor ama biz hiç alışık olmadığımızdan anlayamıyoruz. Ben C ve C++ kodlarında #if 0 kullanmayı biliyorum.

D'de de güzel bir olanağımız var:

Bu konuda hakklısın hocam; bazen ToggleMark benim için de uydurması zor oluyor ama şahsen kod yazarken bir bloğu kolayca devre dışı bıraktırıyor. Bir de bunun çiftli versiyonu var o daha kafa karıştırıcı; hiç germeyeyim :)

Aşağıdaki kod derlendiğinde ekrana 13 satır yazması gerekirken 1 satır yazar:

"13satirSay.write;yok) { satir.writeln; }eCopy.array;"

import std.array,std.stdio;
version = hatayok;
void main () {
  string dosya = "whereTowrite.d";
  auto satirlaraBol = File (dosya).byLineCopy.array;
  int satirSay;
  foreach(satir; satirlaraBol) {
    version(hatavar) { satir.write; }
    version(hatayok) { satir.writeln; }
    satirSay++;
  }
  satirSay.write;
}

Ama bu kodu ilgili değişiklik (lütfen çalışan kod satir.writeln; olsun) kullanırsanız dosya içeriği (buradaki 13 satırlık kodumuz tek bir farkla* ekrana veya " > ÇIKTISI.TXT" parametresi ile dosyaya yazılabilir.

Kaynak kodumuz Windows'da 330 byte iken çıktısı 345 byte olur yani fazladan 13 + 2 byte (ekstrandan 13 sayısı yazıldığından) olur.

Sorun şu: Ben ekstra satır sonu istemiyordum ama içeriği FILE ile almak istiyorum!

Soru ise: Neden write sapıtıyor ve adeta seçmece ya da özet bilgi yansıtıyor?

Aslında cevap belli: Standart akım, çıktı vermek için "\n" karakterini bekliyor ve sıkılınca da o satırda bir yeri kafasına göre seçiyor!

Teşekkürler...

July 05, 2021
On 7/5/21 5:41 PM, Salih Dincer wrote:

> Aşağıdaki kod derlendiğinde ekrana 13 satır yazması gerekirken 1 satır
> yazar:

Ben birden fazla satır yazmasını beklemezdim çünkü hiç satır başı karakteri yazdırılmıyor. Benim denediğim ortam farklı: Bir Linux konsol penceresinde herşey beklediğim gibi tek satırda çıkıyor.

> "13satirSay.write;yok) { satir.writeln; }eCopy.array;"

Yani hata tek satır yazmasında değil, herşeyin üst üste yazılmış gibi çıkmasında. Bunun nedeni, o varsaydığımız ara belleğin senin denediğin Windows ortamında hiç dolmadığı veya hiç '\n' gelmediği için hiç yazdırılmaması olabilir. stdout en sonunda kendi ~this ile sonlanırken veya program sonlanırken stdout'ın ara belleği bizim dışımızda çıkışa gönderiliyor olabilir.

Programın sonuna şun ekleyip dener misin:

  stdout.flush();

İşe yaramazsa, Windows kullananların fikrini almış olmak için İngilizce forumlarda sorman daha iyi olabilir. İşe yararsa, belki de "flush edilmeyen akımın ne göstereceği belirsizdir" gibi bir kural vardır ve bdz şimdi öğreniyoruzdur. (?)

Ali


July 06, 2021

Yanılmışım... :)

Hem de Linux'a artık temelli geçmeye karar verdiren bir yanılgı!

Sorun Windows Console'da çünkü kaynak kodu, başka dosyaya ve düzgün şekilde üstelik 345 byte yazabiliyormuş ama ekrana getirdiğinde seçmece (5, 9 ve 12. satırların sonunda onikişer byte) veri alıyormuş!

Linux'da ise bu sorun yok çünkü orada satır sonu sonlanmaları farklı. Sanırım 1 byte ile ifade ediliyordu. Dosya boyutları şöyle:

Linux System:

317 byte whereTowrite.d
306 byte version(hatavar)
319 byte version(hatayok)

Asıl hata Windows! Nasıl olur 5, 9 ve 12. satırlardan bana seçmece yaparsın! Beni nasıl yanıltırsın :)

Meğer nereye yazılır'dan çok neden görülmez? demek diye sorgulamak lazımmış!

July 06, 2021
On Tuesday, 6 July 2021 at 01:22:26 UTC, Ali Çehreli wrote:
> Programın sonuna şun ekleyip dener misin:
>
>   stdout.flush();
Ben yukardaki cevabını görmeden cevap yazdım ve fark edince hemen şimdi denedim. Sadece seçmece yaptığı veri kümesi değişti:

"15stdout.flush();ok) { satir.write; }LineCopy.array;;"

Bunun dışında hiçbir değişiklik olmadı. Sorun belli ki Windows'un ve/veya cmd'nin nane mollalığı :)
July 05, 2021
On 7/5/21 6:32 PM, Salih Dincer wrote:

> satır sonu sonlanmaları farklı.

Bildiğim kadarıyla, çıkışa yazdırırken programcının o konudan haberi olması gerekmez. Biz hep yalnızca '\n' yazdırırız; platformuna göre gerekirse iki karakterle değiştirilir. Ben öyle biliyorum...

Ali