1 (02.06.2014 19:22:15 отредактировано marikk)

Всем привет. Подскажите пожалуйста как прочитать n-ое количество символов из файла?
Проблема собственно в следующем. В системе установлена кодировка utf-8. В ней русские символы занимают 2 байта. А все библиотечные функции(fread, fgets) считывают определенное количество байт(кроме fgets). Другими словами в случае неудачи теряется один символ.
Пример

  FILE *fin, *fou;

  if ((fin=fopen(argv[1], "r")) == NULL) { // если исходник не открылся выходим
    perror ("Ошибка открытия входного файла");
    exit -1;
  }
  char ts[SZ];
  memset (ts, 0, SZ);

  fread  (ts, 11, 1, fin);
  printf ("%s||| \n", ts);
  fclose(fin);

Алфовитную последовательность выводит так

абвгд?|||

Подскажите пожалуйста как с этим бороться ?

2 (02.06.2014 20:10:19 отредактировано Rizado)

marikk пишет:

fread (ts, 11, 1, fin);

Я не спец по C, но почему считывается 11 байт, а не 12? Получается, что последний символ до конца не прочитан, вот его и не может вывести.

Upd. Вы указываете размер блока для чтения и количество. И при двухбайтовой кодировке последний символ не читается. Попробуйте 12 указать.

ᛈᚺ'ᚾᚷᛚᚢᛁ ᛗᚷᛚᚹ'ᚾᚨᚠᚺ ᚲᛏᚺᚢᛚᚺᚢ ᚱ'lᚷᛖᚺ ᚹᚷᚨᚺ'ᚾᚨᚷᛚ ᚠᚺᛏᚨᚷᚾ

Asus Prime B460M-K, i5-10500, Intel 630 UHD + NVIDIA GeForce RTX3060, DDR4 32 GB, SSD 1TB + HDD 2TB | Linux Mint 22.3 Cinnamon + Windows 11

3

rizado пишет:

Я не спец по C, но почему считывается 11 байт, а не 12? Получается, что последний символ до конца не прочитан, вот его и не может вывести.
Upd. Вы указываете размер блока для чтения и количество. И при двухбайтовой кодировке последний символ не читается. Попробуйте 12 указать.

Пробелы цифры и латинские символы занимают по одному байту. В этом то и вся проблема.

4

marikk пишет:

Пробелы цифры и латинские символы занимают по одному байту. В этом то и вся проблема.

Так у Вас написано:

marikk пишет:

Алфовитную последовательность выводит так

    абвгд?|||

Алфавит-то русский, значит, в данном случае 12 байт.

ᛈᚺ'ᚾᚷᛚᚢᛁ ᛗᚷᛚᚹ'ᚾᚨᚠᚺ ᚲᛏᚺᚢᛚᚺᚢ ᚱ'lᚷᛖᚺ ᚹᚷᚨᚺ'ᚾᚨᚷᛚ ᚠᚺᛏᚨᚷᚾ

Asus Prime B460M-K, i5-10500, Intel 630 UHD + NVIDIA GeForce RTX3060, DDR4 32 GB, SSD 1TB + HDD 2TB | Linux Mint 22.3 Cinnamon + Windows 11

5

rizado пишет:

Алфавит-то русский, значит, в данном случае 12 байт.

Ну алфавит в качестве исходного текста был выбран для наглядности. По условию лабораторной это большой текстовый файл. В котором все русские буквы нужно заменить на следующими за ними по алфавиту.

Предполагаю сделать так.

FILE *fi, fo;

открыть потоки 

while (!feof(fi)) {
   прочитать порцию данных из fi
   перевести в cp1251
   заменить русские символы
   перевести обратно
   записать в fo.
}

6

marikk пишет:

перевести в cp1251

Перед этим рекомендую проверять, русская ли это буква. А то попадёт что-то из испанского или французского алфавита с диакритическими знаками, а вы его в 1251 ab .

ᛈᚺ'ᚾᚷᛚᚢᛁ ᛗᚷᛚᚹ'ᚾᚨᚠᚺ ᚲᛏᚺᚢᛚᚺᚢ ᚱ'lᚷᛖᚺ ᚹᚷᚨᚺ'ᚾᚨᚷᛚ ᚠᚺᛏᚨᚷᚾ

Asus Prime B460M-K, i5-10500, Intel 630 UHD + NVIDIA GeForce RTX3060, DDR4 32 GB, SSD 1TB + HDD 2TB | Linux Mint 22.3 Cinnamon + Windows 11

7

marikk, используй fgetws/c для чтения и соответствующие функции для работы с многобайтовыми символами...
да, учитывая постановку задачи, преподу, возможно, проидётся объяснять, что такое utf-8.

95% процентов проблем находятся между клавиатурой и стулом.

8 (04.06.2014 22:35:39 отредактировано marikk)

Рабочий исходник. Если комy интересно

+ открыть спойлер
#include <wchar.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <locale.h>

#define SZ 300 // размер блока

int main (int argc, char **argv)
{
  if (!setlocale(LC_ALL, "ru_RU.UTF-8")) { // óстанавливаем лоакаль. Необходимо для правильного отображения символов
    perror ("SETLOCALE FAIL");
    exit (-1);
  }

  if (argc < 3) { // проверяем число аргóментов. 1 - имя программы 2 - входной файл 3 - выхлоп
    printf ("Неправильное количество аргóментов. \n");
    exit -1;
  }

  FILE *fin, *fou;

  if ((fin=fopen(argv[1], "r")) == NULL) { // если исходник не открылся выходим
    perror ("Ошибка открытия входного файла");
    exit -1;
  }

  if ((fou=fopen(argv[2], "wa")) == NULL) {  // если выхлоп не открылся закрываем исходник, вываливаемся
    fclose (fin);
    perror ("Ошибка открытия выхлопа");
    exit -1;
  }

  while (!feof (fin)) { // пока lseek в fin не достиг конца файла
    wchar_t ws[SZ];  
    if (fgetws(ws, SZ, fin) == NULL) { // читаем порцию символов
      perror ("Ошибка чтения <-");
      break;
    }
    int i;
    int sz= (int)wcslen(ws);
    for (i=0; i<sz; i++) { // крóтим массив. преобразóем все рóсские символы
      if ( (ws[i] >= 1072 && ws[i] < 1103) || (ws[i] >= 1040 && ws[i] < 1071) )
        ws[i]++;
    }
    if (fputws(ws, fou) < 0) { // записываем
      perror ("Ошибка записи в ->");
      break;
    }
  }
  fclose (fin);
  fclose (fou);
}

Код отрабатывает нормально. Только вот возникает такая ситуация.

Размер файла 10 символов. При первом заходе функция чтения захватывает все данные далее отрабатывает нормально.
Потом выполнение попадает на условие !feof (fin), и почему то выполнение не прерывается. Может я где ошибся ?