Смысл такой: на WEB-сайт потребовалось выгрузить файл в кодировке UTF-8. Но проблема в том, что UTF-8 имеет 2 варианта: «с BOM» и «без BOM». Файлы, сохраненные в этих двух кодировках, получаются одинаковые за исключением того, что в первом случае в начало файла добавлены три байта EF BB BF (в 16-ричной системе счисления). Это и есть символы BOM (сигнатура Byte Order Mark). Так вот, на сайт нужно было отправить «без BOM», а 1с 8.2 сохраняет исключительно «с BOM».
Вот из-за того, что 1с 8.2 не может сохранять текстовые файлы в нужном мне формате и возникла идея «вырезать» эти символы из двоичного файла, но как это сделать в 1с 8.2, я не нашел. Там вообще работа с двоичными данными очень ограничена.
Поэтому пошел по простому пути: что не изобретено, на том катаемся.
Придумал через «очень много» так:
это приблизительный код вызова:
текст = Новый ТекстовыйДокумент;
...
здесь в "текст" что-то пихаем
...
папкаФайла = "какая-то папка";
папкаВОМ = папкаФайла+"temp_BOM";
имяФайла = "как-то.почему-то";
СоздатьКаталог(папкаВОМ);
текст.Записать(папкаВОМ+имяФайла, КодировкаТекста.UTF8, Символы.ВК);
УбитьВОМ(папкаВОМ+имяФайла, папкаФайла+имяФайла, папкаВОМ);
далее непосредственно главная процедура "УбитьВОМ":
Процедура УбитьВОМ(Знач ИсходныйФайл, РезультирующийФайл, ВременнаяПапка, МассивФайлов = Неопределено)
Если МассивФайлов = Неопределено Тогда
МассивФайлов = Новый Массив;
КонецЕсли;
бин = Новый ДвоичныеДанные(ИсходныйФайл);
размер = бин.Размер();
новыйРазмер = Макс(Окр(размер/2,0),3);
массив = РазделитьФайл(ИсходныйФайл,новыйРазмер);
Если массив.Количество() = 2 Тогда
МассивФайлов.Вставить(0,массив[1]);
КонецЕсли;
Если новыйРазмер = 3 Тогда
ОбъединитьФайлы(МассивФайлов,РезультирующийФайл);
УдалитьФайлы(ВременнаяПапка);
Иначе
УбитьВОМ(массив[0],РезультирующийФайл,ВременнаяПапка,МассивФайлов);
КонецЕсли;
КонецПроцедуры
В результате получается файл в кодировке "UTF-8 без BOM".
Примечание. понимаю, что через "ж", но если кто подскажет другой вариант это будет интересно со всех сторон.
А в остальном: кому нужно - пользуйтесь и экспериментируйте.
если в виндах, то можно заюзать ADODB.Stream
например, так:
Показать
синтаксис в примере 7-шный, но код применим для любой версии — 7.7, 8.х, главное, чтобы доступ к объекту ADODB.Stream был
Еще можно провернуть такой танец с бубном (без ВК, работа в памяти, без файлов):
1) получить двоичные данные из файла (как у вас)
2) преобразуем двоичные данные в строку с помощью ЗначениеИзСтрокиВнутр
3) анализируем формат, там не сложно, удаляем лишние переносы кареток (символ 10 вроде) // при желании могу описать подробнее
4) упаковываем поток обратно, получая двоичные данные
5) записываем в файл. Профит
(1) andrewks, отлично отработало в следующем виде:
Процедура УбитьВОМ(ИсходныйФайл,РезультирующийФайл)
Попытка
файл = Новый ComObject(«ADODB.Stream»);
файл.Mode = 3; // r/w
файл.Type = 1; //1-Binary, 2-Text
файл.Open();
файл.LoadFromFile(ИсходныйФайл);
файл.Position = 3;
текстБезБОМ = Новый ComObject(«ADODB.Stream»);
текстБезБОМ.Mode = 3; // r/w
текстБезБОМ.Type = 1; //1-Binary, 2-Text
текстБезБОМ.Open();
файл.CopyTo(текстБезБОМ);
файл.Close();
текстБезБОМ.SaveToFile(РезультирующийФайл,2);
текстБезБОМ.Close();
УдалитьФайлы(ИсходныйФайл);
Исключение
Сообщить(ОписаниеОшибки(),СтатусСообщения.Важное);
КонецПопытки;
КонецПроцедуры
(2) Serj1C, не получилось сотворить такой вариант обработки:
1. при преобразовании «ЗначениеВСтрокуВнутр» 1с преобразует двоичные данные в формат base64, при этом длина строки становится больше размера иходного файла почти в полтора раза, это значит, что у нас уже текст не в кодировке UTF-8.
2. не совсем понятно: символы перевода строки (10) (возврат каретки — 13) обязательно удалять? а если это UTF-ный символ с кодом 10?
3. каким образом «упаковать поток обратно»? у объекта «ДвоичныеДанные» только 2 метода — «Размер()» и «Записать(ИмяФайла»).
4. как записать в файл результат?
пробовал еще такой вариант:
бин = Новый ДвоичныеДанные(ИсходныйФайл);
бинСтрока = Base64Строка(бин);
новаяБинСтрока = Сред(бинСтрока,4);
бин = Base64Значение(новаяБинСтрока);
бин.Записать(РезультирующийФайл);
но там вообще ерунда получается.
может, примерчик рабочий есть?
Тоже долго мучился пока нашел как это сделать для записи текстовых файлов средствами 1С:
УдалитьФайлы(ИмяФайла); // надо убедиться, что файл не существует, т.к. если он существует, то данные добавятся в конец файла
ЗТ = Новый ЗаписьТекста(ИмяФайла,,, Истина, Символы.ПС);
ЗТ.Записать(МояСтрока);
ЗТ.Закрыть();
И никаких извращений…
(6) mc2, шикарный вариант, именно то, что нужно. спасибо!
(5) Serj1C, наворочено как-то. для записи простого файлика в формате csv слишком много телодвижений.
самый простой и подходящий вариант — (6).
хотя для общего развития полезно. спасибо.
(9) тутhttp://infostart.ru/public/137969/ тоже неплохо описан процесс записи произвольных данных в файл
(9) Serj1C,http://infostart.ru/public/137969/ — это то, что написал andrewks (1)
(7) Ну вот, в 8.3.1 без режима совместимости с 8.2.16, этот вариант работать больше не будет! Разработчики вместо того, чтобы делать то,что надо, делают то что не надо! Теперь извращения принимаются.
(4) Собственно так и делаю.
Только у вас ошибка.
Вот рабочий код:
Использовал вВизуализация журнала регистрации Gource
В 8.3 не проверял еще, но думаю должно сработать.
(7) нашел новый способ, который годится и для 8.3:
ЗТ = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.ANSI);
ЗТ.Закрыть();
ЗТ = Новый ЗаписьТекста(ИмяФайла,,, Истина, Символы.ПС);
ЗТ.Записать(Данные);
ЗТ.Закрыть();
(13) mc2, долго смеялся. Действительно, извращения принимаются. Как так удается находить таких блох? За терпение и находчивость — однозначный +.
(12) Gmix, этот вариант попробовал — работает. Спасибо за пример. Я просто в цифирьке ошибся. Бывает.
(6) mc2,
Попробовал твой метод, и выяснил, что за вредные символы отвечает параметр «Дописывать» в конструкторе «ЗаписьТекста»
в общем получилось так:
УдалитьФайлы(имяФайлаОтправки); это да, это обязательно
ЗаписьТекста = Новый ЗаписьТекста(имяФайлаОтправки,КодировкаТекста.UTF8,,Истина,Символы.ПС);
ЗаписьТекста.ЗаписатьСтроку(«—«+boundary);
ЗаписьТекста.ЗаписатьСтроку(«Content-Disposition: form-data; name=»»file»»; filename=»»goods.xml»»»);
ЗаписьТекста.ЗаписатьСтроку(«Content-Type: text/xml»);
ЗаписьТекста.ЗаписатьСтроку(«»);
и ниже пишем содержимое XML файла
СПАСИБО
(16) 1st RUS, Посмотрите пожалуйста (13) пост этой темы, т.к. то, что было написано в (6) не работает в 8.3.
Писал обработку для хеширования по ГОСТ с помощью стороннего EXE. Программка работала через командную строку. Необходимо было указать ей путь к файлу с данными на вход. Она генерила выходной файл с хешем.
Поимел проблему. У меня был тестовый файл и файл сгенеренный 1С, с виду абсолютно одинаковые. Разница в размере в 2 байта. Хеш программа выдавала разный. Оказалось что по умолчанию 1С указывается символ перевода строки и при создании файла и при добавлении строки. Указал в обоих местах в качестве символа «» и все пошло. Использовал много идей из этого поста. Возможно кому то будет полезен полный код.
Функция ПолучитьХЭШГОСТ(СтрокаНаВход)
// очистили входящий файл
УдалитьФайлы(КаталогВременныхФайлов()+»in.txt»);
ТекстIn = Новый ЗаписьТекста(КаталогВременныхФайлов()+»in.txt», КодировкаТекста.UTF8,»», Ложь,);
ТекстIn.ЗаписатьСтроку(Строка(СокрЛП(ВРЕГ(ВходящиеДанные))));
ТекстIn.Закрыть();
// обрезаем ВОМ
ОБ_ДД=Новый ДвоичныеДанные(КаталогВременныхФайлов()+»in.txt»);
Стр_Base64=Base64Строка(ОБ_ДД);
ОБ_ДД=Base64Значение(Сред(Стр_Base64,5));
ОБ_ДД.Записать(КаталогВременныхФайлов()+»in.txt»);
// очистили выходной файл
УдалитьФайлы(КаталогВременныхФайлов()+»out.txt»);
ТекстOut = Новый ЗаписьТекста(КаталогВременныхФайлов()+»out.txt», КодировкаТекста.UTF8,,Ложь,);
ТекстOut.Закрыть();
//запустили приложение хеширования
ЗапуститьПриложение(Строка(ИмяФайла)+» —gost-cryptopro «+КаталогВременныхФайлов()+»in.txt»+» «+»—output=»+КаталогВременныхФайлов()+»out.txt»,,Истина,);
//прочитали из выходного файла результат
Текст = Новый ЧтениеТекста(КаталогВременныхФайлов()+»out.txt», КодировкаТекста.UTF8);
Стр = Текст.ПрочитатьСтроку(«»); //при создании файла перевод строки убрали,при чтении тоже убрали, то есть читаем весь файл как строку
Стр = СтрЗаменить(Стр,Строка(КаталогВременныхФайлов()+»in.txt»),»»);
РезультатХеширования = Врег(Стр);
Возврат РезультатХеширования;
КонецФункции
Кодировка UTF-8 без BOM называется «CESU-8». Подсказали.
(20) ErrorEd88, да ну! и где же об этом написано в описании стандарта?http://www.unicode.org/reports/tr26/
(16) 1st RUS, спасибо за
то что надо!
(20) Спасибо! Помогло!
(20) ErrorEd88, Спасибо!
Информация верная!!! 🙂
(20) ErrorEd88, выручил.
(20) ErrorEd88,
Спасибо помог, очень выручило при склейке csv созданных в фоновых в многопоточной обработке.
(6), Спасибо за совет.
Писал выгрузку на сайт через файл .csv столкнулся с данной проблемой. Перепробовал несколько способов из указанных выше. Нашел для себя наиболее оптимальный следующий метод, который меняет кодировку в уже готовом, ранее сформированном файле .csv
Показать
Варианты с сохранением в промежуточный файл изначально кривое решение. В 20 разумное решение с указанием другой кодировки.
20 -> то что нужно, пробуйте указать кодировку в наглую. Вместо КодировкаТекста.UTF8 ->»CESU-8″
Например:
Запрос.УстановитьТелоИзСтроки(ТекстPOSTЗапроса, «CESU-8»);
(30) в типовой нашел такой код:
Так решил проблему:
(32)