Добавить 4 байта каждый 1 байт в файловый буфер - PullRequest
0 голосов
/ 24 апреля 2020

Я хотел бы добавить 1 байт каждые 4 байта, когда он читает файл в буфер. Как только я использую свой код, он добавляет байты в конец файла вместо каждых 4 байтов. У меня проблемы, и теперь мне нужна помощь, поэтому я здесь. Спасибо за интерес к чтению моего поста.

Вот мой код:

BYTE* ReadFileToMem(WCHAR* szFileName, DWORD& dwSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    BYTE* pFileBuffer = (BYTE*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);


    int allocSize{};
    for (int i = 0; i < dwSize; i++)
    {
        if (i % 4) continue;
        allocSize++;
    }

    int afterSize = allocSize + dwSize;

    BYTE* pFileBufferB = (BYTE*)VirtualAlloc(NULL, afterSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    LPBYTE p = pFileBuffer;
    for (int i = 0; i < dwSize; i++)
    {
        if (i % 4) continue;
        *pFileBufferB = *p;
        pFileBufferB++;
        p++;
    }

    cout << allocSize;

    return pFileBufferB;
}

Ответы [ 3 ]

1 голос
/ 24 апреля 2020

Это идеальная ситуация для изменения локального объекта в потоке для изменения входного потока.

Что вы хотите сделать, это создать std::codecvt фасет и добавить его в локальный и наполнить файловый поток этот местный. После того, как вы это сделаете, поток автоматически добавит пробел каждому четвертому элементу, и вашему коду, использующему поток, не нужно будет ничего делать.

#include <locale>
#include <fstream>
#include <iostream>

// 
class AddSpaceEveryFourthCharacter: public std::codecvt<char,char,mbstate_t>
{
    public:
        using MyType        = std::codecvt<char,char,mbstate_t>;
        using state_type    = MyType::state_type;
        using intern_type   = MyType::intern_type;
        using extern_type   = MyType::extern_type;
        using result        = MyType::result;

        // This indicates that we are converting the input.
        // Thus forcing a call to do_in()
        virtual bool do_always_noconv() const throw()   {return false;}

        // As the buffer is read we read data from "from" and place it
        // into "to". As long as we have at least 4 characters in "from"
        // and at least 5 characters on the "to" we can copy data (and add
        // the extra byte).
        virtual result do_in(state_type& state,
                const extern_type* from, const extern_type* from_end, const extern_type*& from_next,
                intern_type*       to,   intern_type*       to_end,   intern_type*&       to_next
        ) const
        {
            std::size_t fromLen = from_end - from;
            std::size_t toLen   = to_end - to;
            // extract the state of any partial conversions (see below)
            int leftOver = *reinterpret_cast<char*>(&state);

            while(fromLen >= 4 && toLen >= 5) {
                for(int loop = leftOver; loop < 4; ++loop) {
                    *to++ = *from++;
                }
                *to++ = '-';  // You did not specify what the extra byte
                              // was so I guessed at a 'dash'.
                fromLen -= 4;
                toLen   -= 5;
                leftOver = 0;
            }

            // Copy any remaining characters that will fit from "from"
            while(fromLen > 0 && toLen > 0) {
                *to++ = *from++;
                --fromLen;
                --toLen;
                ++leftOver;
            }

            // Keep track of any partial conversions.
            (*reinterpret_cast<char*>(&state))    = static_cast<char>(leftOver);

            // When we have converted as much as possible update the
            // output parameters to show where you got to.
            from_next = from;
            to_next   = to;

            // return the appropriate values.
            return (fromLen == 0) ? ok : partial;
        }
};

int main()
{
    // construct a custom filter locale and add it to a local.
    const std::locale filterLocale(std::cout.getloc(), new AddSpaceEveryFourthCharacter());

    // Create a file, imbue a local and then open the file.
    std::ifstream   file;
    file.imbue(filterLocale);
    file.open("test.data");

    // Now simply use the file as you would normally.
    std::string line;
    while (std::getline(file, line)) {
        std::cout << line << "\n";
    }
}

Когда я запускаю это, я получаю:

> cat test.data
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type specimen book.


> ./a.out
Lore-m Ip-sum -is s-impl-y du-mmy -text- of -the -prin-ting- and- typ-eset-ting- ind-ustr-y.
L-orem- Ips-um h-as b-een -the -indu-stry-'s s-tand-ard -dumm-y te-xt e-ver -sinc-e th-e 15-00s,-
whe-n an- unk-nown- pri-nter- too-k a -gall-ey o-f ty-pe a-nd s-cram-bled- it -to m-ake -a ty-pe s-peci-men -book-.
0 голосов
/ 24 апреля 2020

вам нужно просто выделить буфер ((file_size + 3) >> 2 ) * 5 для результата удержания. и затем перемещать данные в нем от конца к началу - в этом случае мы можем делать все в одном буфере без дополнительного выделения

void ModifyBuffer(PULONG puFrom, ULONG NumberOfBytes /* != 0*/, UCHAR ExtraByte = 0)
{
    NumberOfBytes = (NumberOfBytes + 3) >> 2;

    union {
        PBYTE pbTo;
        PULONG puTo;
    };

    puFrom += NumberOfBytes, pbTo = (PBYTE)puFrom + NumberOfBytes;

    do 
    {
        *--pbTo = ExtraByte;
        *--puTo = *--puFrom;
    } while (--NumberOfBytes);
}

и всего кода:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
    return f ? NOERROR : GetLastError();
}

ULONG ReadFileToMem(PCWSTR szFileName)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    FILE_STANDARD_INFO fsi;

    ULONG dwError = BOOL_TO_ERROR(GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)));

    if (dwError == NOERROR)
    {
        ULONG64 dwRequiredSize = ((fsi.EndOfFile.QuadPart + 3) >> 2 ) * 5;

        if (!fsi.EndOfFile.QuadPart)
        {
            dwError = ERROR_BUFFER_ALL_ZEROS;
        }
        else if (dwRequiredSize > MAXULONG)
        {
            dwError = ERROR_FILE_TOO_LARGE;
        }
        else
        {
            if (PVOID buf = LocalAlloc(0, (size_t)dwRequiredSize))
            {
                ULONG NumberOfBytes;

                dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, fsi.EndOfFile.LowPart, &NumberOfBytes, 0));

                if (NOERROR == dwError)
                {
                    if (NumberOfBytes)
                    {
                        ModifyBuffer((PULONG)buf, NumberOfBytes);
                    }
                    else
                    {
                        dwError = ERROR_BUFFER_ALL_ZEROS;
                    }
                }

                LocalFree(buf);
            }
            else
            {
                dwError = GetLastError();
            }
        }
    }

    CloseHandle(hFile);

    return dwError;
}
0 голосов
/ 24 апреля 2020

Убедитесь, что указатель приращения введен в l oop. Также необходимо избегать утечек памяти:

#include <windows.h>
#include <iostream>
BYTE* ReadFileToMem(WCHAR* szFileName, DWORD& dwSize,DWORD& ByteSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    BYTE* pFileBuffer = (BYTE*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);


    int allocSize{};
    for (int i = 1; i <= dwSize; i++)
    {
        if (i % 4) continue;
        allocSize++;
    }

    ByteSize = allocSize + dwSize;

    BYTE* pFileBufferB = (BYTE*)VirtualAlloc(NULL, ByteSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    BYTE* pp = pFileBufferB;
    LPBYTE p = pFileBuffer;
    for (int i = 1; i <= dwSize; i++, p++, pp++)
    {
        *pp = *p;
        if (i % 4 == 0)
        {
            pp++;
            *pp = '*';
        }

    }

    std::cout << allocSize;
    VirtualFree(pFileBuffer, dwSize, MEM_RELEASE);
    return pFileBufferB;
}
int main()
{
    DWORD dwSize = 0;
    DWORD ByteSize = 0;
    WCHAR file[] = L"test.txt";
    BYTE* pFileBufferB = ReadFileToMem(file, dwSize, ByteSize);
    //To Do;
    VirtualFree(pFileBufferB, ByteSize, MEM_RELEASE);
    return 0;
}

Или использовать std::string::insert(index,std::string):

#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
std::string ReadFileToMem(WCHAR* szFileName, DWORD& dwSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    CHAR* pFileBuffer = (CHAR*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);
    std::string tmp = pFileBuffer;
    VirtualFree(pFileBuffer, dwSize, MEM_RELEASE);
    for (int i = dwSize; i > 0; i--)
    {
        if (i % 4) continue;
        tmp.insert(i,"*");
    }

    return tmp;
}
int main()
{
    DWORD dwSize = 0;
    DWORD ByteSize = 0;
    WCHAR file[] = L"test.txt";
    std::string pFileBufferB = ReadFileToMem(file, dwSize, ByteSize);
    std::cout << pFileBufferB;
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...