Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
1

"Вшить" в файл имя файла. Или как из string перевести в byte[]

13.02.2015, 11:27. Показов 1896. Ответов 11
Метки нет (Все метки)

Здравствуйте. Считываю файл, получаю массив байтов. Сохраняю его имя, расширение, хеш в переменные. Делаю различные операции с массивом байтов, и снова записываю в файл (File.WriteAllBytes(path, ByteFile)); Но мне помимо самого файла надо "вшить" в него имя, расширение, хеш. Как это правильно делать чтобы потом можно было легко их считать из файла и использовать в дальнейшем? Проблема в том, что имя файла, расширение - string. Не знаю как их преобразовать чтобы потом дозаписать их в файл. Находил функцию:

C#
1
2
3
4
5
6
 static byte[] GetBytes(string str)
        {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }
Но она как по мне некорректно переводит строку в массив байтов (получается массив, в котором через значение пишется 0, т.е. например 18, 0, 12, 0, 1, 0 и т.д. что на мой взгляд неправильно)

С хешем немного проще, так как четное кол-во символов, то использую такое преобразование:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
       Hash = ConvertHexToBin(Hash);
                    byte[] byteHash = new byte[Hash.Length / 8];
                    string[] HashParts = new string[Hash.Length / 8];
                    int counter = 0;
 
                    for (int i = 0; i < Hash.Length; i++)
                    {
                        if ((i % 8 == 0) && (i != 0))
                            counter++;
                        HashParts[counter] += Hash[i];
                    }
                    for (int i = 0; i < byteHash.Length; i++)
                    {
                        byteHash[i] = Convert.ToByte(HashParts[i], 2);
                    }
                    HashByte = byteHash;
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.02.2015, 11:27
Ответы с готовыми решениями:

Как перевести byte[] или переменную типа IntPtr к типу byte[] (ассемблерные инструкции)?
Наткнулась на проблему, нужно перевести тип IntPtr в массив ассемблерной инструкции. Вот пример...

Windows 7 и DirectX: "Не удалось найти имя типа или пространства имен "Device"
Попробовал ниписать простенькую програмку (вращать треугольники), брал пример сосвоими доработками....

Можно ли во время выполнения "извлечь" имя приложения, имя класса, имя исполняемого метода и пр. ?
или какие-нубдь &quot;квазипеременные&quot; компилятора, позволяющие их использовать?

Текстовый файл. строка с 3 "объектами" разделенные разделителем "," как обратиться к каждому из объектов?
Всем добрый день. Имеется текстовый файл. содержимое: более 31.000 строк. каждая строка...

11
Администратор
Эксперт .NET
13245 / 10782 / 4448
Регистрация: 17.03.2014
Сообщений: 21,768
Записей в блоге: 1
13.02.2015, 15:08 2
Лучший ответ Сообщение было отмечено Psilon как решение

Решение

DEMON_RUS, при переводе строки в массив байтов надо понимать какая кодировка используется в этот момент. В твоем примере используется кодировка UTF-16 потому что строки в .NET хранятся именно в этой кодировке. Это многобайтовая кодировка из семейства Unicode и она тратит как минимум 2 байта на один символ. Именно отсюда берутся "неправильные нули". Есть более короткий способ превратить строку в массив байтов и обратно в строку используя методы Encoding.GetBytes() и Encoding.GetString()
C#
1
2
3
string text = "qqqЙЙЙ";
byte[] bytes = Encoding.UTF8.GetBytes(text);
string text2 = Encoding.UTF8.GetString(bytes);
Здесь используется кодировка UTF-8 которая гарантирует сохранение всех символов и менее расточительна чем UTF-16.

Что касается правильного решения, то можно самому писать байты или использовать BinaryReader/BinaryWriter. Тебе решать как лучше.

P.S. Советую прочитать статью Джоэля Спольски Абсолютный Минимум, который Каждый Разработчик Программного Обеспечения Обязательно Должен Знать о Unicode и Наборах Символов.
2
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
13.02.2015, 18:57  [ТС] 3
Спасибо, то что надо)

Добавлено через 41 минуту
Немного покопавшись появилась необходимость в следующем:
Имеется скажем файл test.txt Шифруем его (массив битов), записывает в новый файл под новым названием (помимо самого файла, в него надо спрятать имя файла, контрольную сумму(хеш) чтобы при расшифровании восстановить имя и убедиться в целостности файла). Как вообще это происходит и реализуется?
Контрольная сумма имеет фиксированную длину, с ней в принципе проблем нет - дозаписал её в файл, и при расшифровке уже знаешь, что первые N бит приходится на контрольную сумму, а остальные биты это файл. С именем как поступать не понимаю.. Скажем тот же файл test.txt - 8 символов. 8 по таблице ASCII есть 56. Но что если длина имени файла 88 символов? Тогда придется дозаписывать 5656. Но в итоге сколько символов отводится под название файла - неизвестно.. Подскажите, пожалуйста, как этот механизм работает.
0
Администратор
Эксперт .NET
13245 / 10782 / 4448
Регистрация: 17.03.2014
Сообщений: 21,768
Записей в блоге: 1
13.02.2015, 19:07 4
DEMON_RUS, чтобы не вводить ограничения на длину записываем перед самой строкой длину в символах или байтах. Классы BinaryWriter/BinaryReader уже умеют это делать.
1
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
13.02.2015, 19:48  [ТС] 5
Не понял( Уточню - вот к примеру:
На первой фотке я пытаюсь зашифровать файл с именем в 5 символов (1.txt) - FileNameByte (Имя файла в байтовом представлении).
FileNameLengthByte - содержит числовое значение длины имени в байтовом представлении (число 5, т.е. по таблице ASCII это 53). Я записываю в начало файла эти цифры. При расшифровке когда считываю эту цифру 53, по таблице я узнаю, что 53 = это цифра 5, т.е. последующие 5 байт считываемого файла - это имя файла.

Во втором случае пытаюсь зашифровать файл с именем в 68 символов (отсюда знаю, что при расшифровке первые 68 символов это имя файла)
Но когда пытаюсь записать в начало файла именно число, свидетельствующее о длине имени файла (FileNameLengthByte) то уже будет записываться не 53, коды 6 и 8, т.е. уже 4 бита - 54 56.

В итоге для первого случая чтобы узнать длину имени надо считать 2 первых бита (53), а во втором 4 бита (54, 56). Но откуда опять узнать сколько надо считать? Сам уже запутался..

Или по другому: возможно нужно чтобы числа (однозначное, двухзначное, трёхзначное) записывались всегда фиксированной длиной. Скажем 4 в бинарной форме будет 0000 0100, 158 будет 1001 1110 и т.д. Т.е. Всегда придется считывать 8 первых бит.. Походу этот вариант вы и предложили..)
0
Миниатюры
"Вшить" в файл имя файла. Или как из string перевести в byte[]   "Вшить" в файл имя файла. Или как из string перевести в byte[]  
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
13.02.2015, 19:58  [ТС] 6
Если брать большее число - скажем 896 - то уже 10 разрядов необходимо использовать( (Хотя с другой стороны имена такой длины думаю никто не использует, но предусмотреть это всё же как-то надо..)
0
Администратор
Эксперт .NET
13245 / 10782 / 4448
Регистрация: 17.03.2014
Сообщений: 21,768
Записей в блоге: 1
13.02.2015, 20:42 7
DEMON_RUS, число хранится в памяти как набор байтов фиксированной длины. Например, для int это всегда 4 байта. Записывать и читать нужно именно байты, а не строкое представление которое может иметь разную длину. Вот два примера чтения/записи данных. Первый записывает имя файла используя возможности BinaryWriter. Второй преобразует имя файла в массив байтов и записывает его длину перед записью массива. Оба примера записывают массивы HashByte, byteS, encByteFile после имени файла. Также приведен пример чтения данных обратно. Я не понял что хранит массив byteS. Исходил из того что его длина всегда 8 байтов.
пример раз
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const int HASH_BYTES = 16;
const int DONT_KNOW_WHAT_BYTES = 8;
 
// Запись
string outputPath = Path.Combine(path, "test" + Extension);
using (var fstream = File.OpenWrite(outputPath))
using (var binWriter = new BinaryWriter(fstream))
{
    // BinaryWriter запишет строку с указанием её длины
    binWriter.Write(fileName);
    
    // Массивы byteS и HashByte имеют фиксированную длину поэтому записывать из длину не надо
    binWriter.Write(byteS, 0, byteS.Length);
    binWriter.Write(HashByte, 0, HashByte.Length);
    
    // Длина encByteFile может быть разной, но записывать его длину не нужно т.к.
    //  он идет до конца файла
    binWriter.Write(encByteFile, 0, encByteFile.Length);
}
 
// ..................
 
// Чтение
string fileName;
byte[] byteS, HashByte, encByteFile;
using (var fstream = File.OpenRead(inputPath))
using (var binReader = new BinaryReader(fstream))
{
        // Читаем строку ровно той длины которой мы записали т.к. перед строкой указана её длина
        // и BinaryReader знает когда нужно остановиться
    fileName = binReader.ReadString();
    
    byteS = binReader.ReadBytes(DONT_KNOW_WHAT_BYTES);
    HashByte = binReader.ReadBytes(HASH_BYTES);
    
    // Вычисляем размер оставшихся данных
    int dataLength = (int)(fstream.Length - fstream.Position).Dump();
    encByteFile = binReader.ReadBytes(dataLength);
}

пример два
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const int HASH_BYTES = 16;
const int DONT_KNOW_WHAT_BYTES = 8;
 
// Запись
string outputPath = Path.Combine(path, "test" + Extension);
using (var fstream = File.OpenWrite(outputPath))
using (var binWriter = new BinaryWriter(fstream))
{
    byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName);
    binWriter.Write(fileNameBytes.Length); // Записываем 4 байта с длиной имени файла в байтах
    binWriter.Write(fileNameBytes, 0, fileNameBytes.Length); // Записываем имя файла
    
    // Массивы byteS и HashByte имеют фиксированную длину поэтому записывать из длину не надо
    binWriter.Write(byteS, 0, byteS.Length);
    binWriter.Write(HashByte, 0, HashByte.Length);
    
    // Длина encByteFile может быть разной, но записывать его длину не нужно т.к.
    //  он идет до конца файла
    binWriter.Write(encByteFile, 0, encByteFile.Length);
}
 
// ..................
 
// Чтение
string fileName;
byte[] byteS, HashByte, encByteFile;
using (var fstream = File.OpenRead(inputPath))
using (var binReader = new BinaryReader(fstream))
{
        // Читаем длину имени файла в байтах
    int nameLengthBytes = binReader.ReadInt32();
    byte[] fileNameBytes = binReader.ReadBytes(nameLengthBytes);
        // Получаем имя файла. Важно чтобы при записи и чтении использовалась одинаковая кодировка
    fileName = Encoding.UTF8.GetString(fileNameBytes);
    
    byteS = binReader.ReadBytes(DONT_KNOW_WHAT_BYTES);
    HashByte = binReader.ReadBytes(HASH_BYTES);
    
    // Вычисляем размер оставшихся данных
    int dataLength = (int)(fstream.Length - fstream.Position).Dump();
    encByteFile = binReader.ReadBytes(dataLength);
}
1
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
14.02.2015, 00:50  [ТС] 8
OwenGlendower, первое что бросилось в глаза - первый пример, чтение.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Чтение
string fileName;
byte[] byteS, HashByte, encByteFile;
using (var fstream = File.OpenRead(inputPath))
using (var binReader = new BinaryReader(fstream))
{
        // Читаем строку ровно той длины которой мы записали т.к. перед строкой указана её длина
        // и BinaryReader знает когда нужно остановиться
    fileName = binReader.ReadString();
    
    byteS = binReader.ReadBytes(DONT_KNOW_WHAT_BYTES);
    HashByte = binReader.ReadBytes(HASH_BYTES);
    
    // Вычисляем размер оставшихся данных
    int dataLength = (int)(fstream.Length - fstream.Position).Dump();
    encByteFile = binReader.ReadBytes(dataLength);
}
По сути порядок действий такой:
Запускаем программу, указываем файл, нажимаем расшифровать - больше никаких данных по сути у нас нету, кроме ключа.
Далее нам нужно считать из файла имя файла, byteS - это синхропосылка, хеш, и сам файл.


// Читаем строку ровно той длины которой мы записали т.к. перед строкой указана её длина
// и BinaryReader знает когда нужно остановиться
fileName = binReader.ReadString();
Считали допустим имя файла. На этом этапе нам ничего больше неизвестно, как мы можем принимать эти параметры (DONT_KNOW_WHAT_BYTES, HASH_BYTES), если они пока что неизвестны нам?
C#
1
2
   byteS = binReader.ReadBytes(DONT_KNOW_WHAT_BYTES);
    HashByte = binReader.ReadBytes(HASH_BYTES);
И что надо подключить, чтобы Dump() заработал?

Добавлено через 8 минут
Пока писал, понял, что это не какой-то параметр, а уже известная фиксированная длина переменных.. Туплю что-то(
На счёт дампа вопрос в силе
0
Администратор
Эксперт .NET
13245 / 10782 / 4448
Регистрация: 17.03.2014
Сообщений: 21,768
Записей в блоге: 1
14.02.2015, 01:06 9
Цитата Сообщение от DEMON_RUS Посмотреть сообщение
И что надо подключить, чтобы Dump() заработал?
Это метод из LINQPad где я тестировал код. Он не нужен для работы. Забыл убрать

Цитата Сообщение от DEMON_RUS Посмотреть сообщение
понял, что это не какой-то параметр, а уже известная фиксированная длина переменных
Так точно.
1
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
14.02.2015, 01:17  [ТС] 10
OwenGlendower, Премного благодарен за помощь Всё отлично работает, и код стал намного проще..)
0
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
23.02.2015, 18:33  [ТС] 11
Возник ещё вопрос: почему не хотят записывать в файл ни binWriter.Write() ни File.WriteAllBytes()?
Все параметры есть для этого, всё правильно вроде, но после выполнения этого кода файл не появляется.. В чем может быть проблема? Использовал binWriter.Write() и File.WriteAllBytes() при шифровании, всё работало отлично, но вот при расшифровывании почему-то не работает..
0
Миниатюры
"Вшить" в файл имя файла. Или как из string перевести в byte[]  
3 / 2 / 1
Регистрация: 13.05.2013
Сообщений: 234
23.02.2015, 20:43  [ТС] 12
Разобрался, вопрос снимается)
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.02.2015, 20:43

LINQ: Невозможно преобразовать "лямбда-выражение" к типу "string", поскольку он не является делегатом
Здравствуйте. Делаю приложение с использованием Entity Framework. Все было нормально, пока не...

Не удалось привести тип объекта "System.String" к типу "System.Byte[]"."
Имеется код для получения картинки из бд ,но выбивает ошибку Не удалось привести тип объекта...

Можно ли "вшить" файл базы SQLite в программу?
Здравствуйте. Возник такой вопрос. Не получается найти ответ :( Возможно ли &quot;вшить&quot; файл sqlite...

Имя типа или пространство имен "Object" отсутствует в пространстве имен "System.Data"
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.