1

Тема: Кодування файлу

Як в Python записати utf-8 текст у файл, щоб кінець стрічки

\n

вірно інтерпретувався?

Ось як я записую текст у файл, якщо в тексті лише англійські букви і цифри:

def write_csv_to_dir(x, csv_path, var_filename):
    if (x.text):
        with open(csv_path + var_filename, 'w') as f:
          print(x.text, file=f)
   else:
        with open(csv_path + var_filename, 'w') as f:
          print('The content is empty.', file=f)

Однак якщо в тексті трапляються цікаві символи, наприклад китайські ієрогліфи, то отримую такі помилки:

'ascii' codec can't encode character '\uff1a' in position 289624: ordinal not in range(128)

'ascii' codec can't encode character '\xe8' in position 286495: ordinal not in range(128)

Тоді я додав кодування utf-8:

print(x.text.encode('utf-8'), file=f)

В такому вигляді текст із китайськими ієрогліфами зберігається коректно, однак файл тепер виглядає як величезна суцільна стрічка. Бо символ кінця стрічки

\n

інтерпретується як текст і стрічка не переноситься.
Підкажіть хто шарить плз.

2

Re: Кодування файлу

Tupo, ale moja hadka taka: sprobuj za dopomohoju toho g unikodu, de novyj rjad mogna zapysaty za dopomohoju zakoda.

Подякували: leofun011

3

Re: Кодування файлу

Тему виділено і перенесену у відповідний форум.

4

Re: Кодування файлу

frz написав:

однак файл тепер виглядає як величезна суцільна стрічка. Бо символ кінця стрічки

\n

інтерпретується як текст

Де виглядає? Чим інтерпретується? Ви розумієте, що не існує абсолютного "правильного" представлення, а є лише різні кодування - і якщо щось виглядає неправильно, то проблема може бути як із боку кодування, так і з боку декодування? Вказуйте це.

Вам потрібно не кодувати стрічку (яка і так в utf-8), тим більше що encode робить з неї bytes, а print знову перетворює на стрічку, а вказувати кодування при відкритті файлу:

with open(csv_path + var_filename, 'w', encoding='utf-8') as f:

Тепер перекодування UTF-8 => ASCII не відбуватиметься.
Ще можна виставити правильну локаль, щоб open підтягав коректні налаштування, приблизно

import locale
locale.setlocale(locale.LC_ALL, 'uk_UA.utf-8')
Подякували: dot, frz, 0xDADA11C7, leofun014

5

Re: Кодування файлу

koala

with open(csv_path + var_filename, 'w', encoding='utf-8') as f:

Дякую, працює.

6 Востаннє редагувалося frz (27.02.2021 02:23:54)

Re: Кодування файлу

Цього разу дотичне питання дещо більш комплексне.

Отже, на стороні клієнта я отримую дані в такому вигляді:

/*header:*/ T1,T2,CURRENT_TIMESTAMP_X
/*row:*/ 123,234,2021-02-26 13:11:33.847000-08:00
/*row:*/ 567,678,2021-02-26 13:11:33.847000-08:00

коментарі header i row мої, щоб показати що я отримую їх рядок за рядком. Потрібно визначитися, як саме кумулювати ці значення в єдину змінну, причому щоб змінна була не єдиною суцільною стрічкою, а порядково:

T1,T2,CURRENT_TIMESTAMP_X
123,234,2021-02-26 13:11:33.847000-08:00
567,678,2021-02-26 13:11:33.847000-08:00

Далі я передаю цю змінну як POST параметр (в тілі запиту).
Наступним кроком на боці сервера я зберігаю це значення як контент файлу.

Якщо я застосовую на боці клієнта просто конкатенацію, то значення склеюються в одну стрічку. Якщо додаю "\n" (стандартний стрічковий делімітер в Python), то в результуючому файлі стрічка виглядає ось так:

T1,T2,CURRENT_TIMESTAMP_X\n123,234,2021-02-26 13:11:33.847000-08:00\n567,678,2021-02-26 13:11:33.847000-08:00

Потрібна підказка збоку, яким типом даних для змінної краще скористатися і як саме...

Upd: Проблема що при передачі в тіло POST запиту я повинен трансформувати це значення за допомогою str()...

----

Upd: Використав json array. Щоправда, на стороні клієнта потрібно робити валідацію перед тим як надсилати на сервер. А коли валідація не проходить з певних причин (скажімо, на клієнт приходять дані де в стрічці трапляється один символ подвійних лапок), тоді потрібно буде прикрутити сповіщення в слак і на email...

7

Re: Кодування файлу

При тестуванні на реальних даних все ж виявилося, що json array не підходить через непередбачуваність даних.

Поки що нижче - мій поточний робочий варіант. Якщо спробувати коротко описати ци виверти, то додати нову стрічку в існуючий файл можна коректно лише за допомогою list, тож щоб у файлі з'явилася нова стрічка у вигляді

123,234,456,678,2021-02-28 01:02:03.001

потрібно з неї спершу зробити list:

['123', '234', '456', '678', '2021-02-28 01:02:03.001']

Виглядає як overengineering, однак працює; тест на реальних даних покаже чи це вже фінальне рішення чи ще ні.

import csv

def csv_append(csv_path, filename, line, var_delimiter):
    with open(csv_path + filename, 'a') as f:
        writer = csv.writer(f, delimiter=var_delimiter)
        writer.writerow(line)
    f.close()

var_delimiter = ','

var_multiliner = '''t1,t2,t3,t4,timestamp_x
123,234,456,678,2021-02-28 01:02:03.001
223,234,456,678,2021-02-28 01:02:03.001
323,234,456,678,2021-02-28 01:02:03.001'''

var_multiliner2 = '''t1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''

x_list = var_multiliner2.split("\n")

i = 0
for x in x_list:
  print("\n" + str(i) + ": ")
  print(x)
  y_list = x.split(var_delimiter)
  j = 100
  yy = []
  for y in y_list:
    print("\n" + str(j) + ": ")
    print(y)
    yy.append(str(y))
    j = j + 1
  print("\nyy: " + str(yy))
  csv_append("/tmp/", "test1234.csv", yy, var_delimiter)
  i = i + 1

8

Re: Кодування файлу

frz написав:
i = 0
for x in x_list:
  ...
  i = i + 1

Це має сталу форму в Python:

for i, x in enumerate(x_list):
  ...

Ну і спершу ви робите

import csv

а потім не використовуєте його, а формуєте файл вручну, ще й вкрай неефективно (відкриваєте-закриваєте його на кожній ітерації). Не треба так.

Подякували: leofun011

9

Re: Кодування файлу

Так, це мій ровер винайдений серед ночі і зафіксований тут що не забути.
Перед тим як винаходити цей ровер, спершу перепробував масу готових прикладів із stack overflow які не дають потрібного результату для моїх умов...
Зайве, неефективне - тут погоджуся.

10

Re: Кодування файлу

трохи покращив...

def csv_append(file, line):
    file.write(line)

def csv_truncate(file):
    file.truncate()

var_delimiter = ','

var_multiliner = '''t1,t2,t3,t4,timestamp_x
123,234,456,678,2021-02-28 01:02:03.001
223,234,456,678,2021-02-28 01:02:03.001
323,234,456,678,2021-02-28 01:02:03.001'''

#print(var_multiliner)

csv_path = "/tmp/"
filename = "test1234.csv"
var_multiliner2 = '''ddd1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''

#print(var_multiliner2)

x_list = var_multiliner2.split("\n")

#i = 0
try: 
  s = open(csv_path + filename, 'w')
  csv_truncate(s)
except Exception as error:
  print("Something went wrong when trying to truncate the file: ", error)
finally:
  s.close()
try:
  f = open(csv_path + filename, 'a')
  for x in x_list:
    #print("\n" + str(i) + ": ")
    #print(x)
    y_list = x.split(var_delimiter)
    j = 1
    #yy = []
    yy_str = ""
    for y in y_list:
      #print("\n" + str(j) + ": ")
      #print(y)
      #yy.append(str(y))
      var_if_delimiter = ""
      if j < len(y_list):
        var_if_delimiter = var_delimiter
      else:
        var_if_delimiter = ""
      print("\nvar_if_delimiter = " + var_if_delimiter + "\n")
      print("\ny = " + y + "\n")
      yy_str = yy_str + y + var_if_delimiter
      j = j + 1
    #print("\nyy: " + str(yy))
    csv_append(f, yy_str + "\n")
    #i = i + 1
except Exception as error:
  print("Something went wrong when writing to the file: ", error)
finally:
  f.close()
#csv_append("/tmp/", "test1234.csv", ['12345678','67898','346536365'], var_delimiter)

11

Re: Кодування файлу

Вибачте, а чим це принципово відрізняється від

csv_path = "/tmp/"
filename = "test1234.csv"
var_multiliner2 = '''ddd1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''
with open(csv_path + filename, "w") as f:
  f.write(var_multiliner2)

?

Подякували: leofun011

12

Re: Кодування файлу

чим це принципово відрізняється

я поки що не можу предметно дискутувати, сам не знаю що написав але працює  :D

13 Востаннє редагувалося koala (28.02.2021 22:32:35)

Re: Кодування файлу

Просто у вас початкові дані в csv і результат у файлі в csv - нащо проміжні перетворення?

14 Востаннє редагувалося frz (28.02.2021 22:36:51)

Re: Кодування файлу

початкові дані в csv

Це не так.

1) Клієнт отримує дані з бази, вони на клієнті тимчасово зберігаються не в файлі а в змінній (а навіть якщо би й зберегти ці дані в csv на клієнті - це буде зайве, бо для наступного кроку файл не має сенсу).
2) Клієнт передає дані через API запитом POST де в тілі запиту - змінна з даними.
3) API сервер зберігає дані в csv
4) Нарешті файл csv передається в сторонній файлообмінник.

Так от, цитований вище код працює над пунктом (3). На сервер API я не можу передати саме файл csv - лише дані з вмістом для файлу. В тому якраз і причина моїх танців з бубном. І вже наче добився результату. Тільки щоб остаточно перевірити, мені потрібен доступ на прод, а на вихідних доступ відключений.

15

Re: Кодування файлу

Але в тілі запиту іде саме тіло CSV-файла, правильно? То й зберігайте його, нащо розбирати на частини те, що вже ціле?

16 Востаннє редагувалося frz (28.02.2021 22:55:16)

Re: Кодування файлу

var_multiliner2 = '''ddd1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''

ось в такому вигляді дані приходять на API сервер:

ddd1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001

і якщо зберігати в файл як є, то остаточний вигляд буде точно таким (одна здоровенна суцільна стрічка), перенос рядка \n не враховується; відповідно потрібно спершу розпарсити на рядки.

---

Хоча... спробую мою останню версію ще раз без розбивання на стрічки.

17

Re: Кодування файлу

Тю, дійсно.... Працює без тих вивертів. Дякую за погляд збоку!
Ще завтра спробую на реальних даних.

def csv_append(file, line):
    file.write(line)

def csv_truncate(file):
    file.truncate()

var_delimiter = ','

var_multiliner = '''t1,t2,t3,t4,timestamp_x
123,234,456,678,2021-02-28 01:02:03.001
223,234,456,678,2021-02-28 01:02:03.001
323,234,456,678,2021-02-28 01:02:03.001'''

csv_path = "/tmp/"
filename = "test4321.csv"
var_multiliner2 = '''dddjk1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''

try: 
  s = open(csv_path + filename, 'w')
  csv_truncate(s)
except Exception as error:
  print("Something went wrong when trying to truncate the file: ", error)
finally:
  s.close()

try: 
  h = open(csv_path + filename, 'w')
  csv_append(h, var_multiliner2)
except Exception as error:
  print("Something went wrong when trying to write into the file: ", error)
finally:
  h.close()

18 Востаннє редагувалося frz (28.02.2021 23:39:51)

Re: Кодування файлу

Ще простіше, оскільки при записі даних в файл одним значенням попередній транкейт файлу непотрібний:

csv_path = "/tmp/"
filename = "test4321.csv"
var_multiliner2 = '''cbadddjkmn1,t2,t3,t4,timestamp_x\n123,234,456,678,2021-02-28 01:02:03.001\n223,234,456,678,2021-02-28 01:02:03.001\n323,234,456,678,2021-02-28 01:02:03.001'''

try: 
  h = open(csv_path + filename, 'w')
  h.write(var_multiliner2)
except Exception as error:
  print("Something went wrong when trying to write into the file: ", error)
finally:
  h.close()

Не розумію що саме мене наштовхнуло йти такими хащами. Але завтра ще переконаюся на реальних даних що все дійсно так просто.

19

Re: Кодування файлу

Обломіссімо :(
В середовищі amazon linux це не працює.
Як мінімум, потрібно буде адаптувати останню версію щоб мультилайнер сплітився відповідно до "\n" делімітеру.

20

Re: Кодування файлу

Будь ласка, замість "не працює" пишіть конкретно, що відбувається.