Skip to main content

Notifications

Community site session details

Community site session details

Session Id :
Small and medium business | Business Central, N...
Answered

Insert multiples file from zip

(1) ShareShare
ReportReport
Posted on by 62
I have one zip file with multiple pdf and and i want to attached those pdf files properly. Currently attachment are inserting with all corrects details including primary keys but when we open pdf file it show some random file details with some blank pages.
Logic given below for refence 
Thanks in advance
 
local procedure ImportAttachmentsFromZip()
    var
        FileMgt: Codeunit "File Management";
        DataCompression: Codeunit "Data Compression";
        TempBlob: Codeunit "Temp Blob";
        EntryList: List of [Text];
        EntryListKey: Text;
        ZipFileName: Text;
        FileName: Text;
        FileExtension: Text;
        InStream: InStream;
        EntryOutStream: OutStream;
        EntryInStream: InStream;
        SelectZIPFileMsg: Label 'Select ZIP File';
        FileCount: Integer;
        DocAttach: Record "Document Attachment";
        ImportedMsg: Label '%1 attachments imported successfully.';
        TableID: Integer;
        RecordNo: Code[20];
        LineNo: Integer;
        ID: Integer;
        DocType: Enum "Purchase Document Type";
        FileNameParts: List of [Text];
        RecRef: RecordRef;
        InvalidFormatErr: Label 'File name "%1" does not match expected format: {TableID}_{RecordNo}_{DocType}_{LineNo}_{ID}_{FileName}.{ext}';
        RecordNotFoundErr: Label 'Record "%1" not found in table %2.';
        InvalidValueErr: Label 'Invalid value "%1" for field %2.';
    begin
        // Upload zip file
        if not UploadIntoStream(SelectZIPFileMsg, '', 'Zip Files|*.zip', ZipFileName, InStream) then
            Error('');
        // Extract zip file and store files to list type
        DataCompression.OpenZipArchive(InStream, false);
        DataCompression.GetEntryList(EntryList);
        FileCount := 0;
        // Loop files from the list type
        foreach EntryListKey in EntryList do begin
            FileName := FileMgt.GetFileName(EntryListKey);
            FileExtension := FileMgt.GetExtension(EntryListKey);
            // Expecting file name format: {TableID}_{RecordNo}_{DocType}_{LineNo}_{ID}_{FileName}.{ext}
            FileNameParts := FileName.Split('_'); // Use '_' as delimiter (adjust if needed)
            if FileNameParts.Count < 6 then
                Error(InvalidFormatErr, FileName);
            // Parse and validate fields with error handling
            if not Evaluate(TableID, FileNameParts.Get(1)) then
                Error(InvalidValueErr, FileNameParts.Get(1), 'Table ID');
            RecordNo := FileNameParts.Get(2); // Code[20] can be assigned directly
            if not Evaluate(DocType, FileNameParts.Get(3)) then
                Error(InvalidValueErr, FileNameParts.Get(3), 'Document Type');
            if not Evaluate(LineNo, FileNameParts.Get(4)) then
                Error(InvalidValueErr, FileNameParts.Get(4), 'Line No.');
            if not Evaluate(ID, FileNameParts.Get(5)) then
                Error(InvalidValueErr, FileNameParts.Get(5), 'ID');
            // Reconstruct the file name (handle underscores in the file name)
            FileNameParts.RemoveRange(1, 5); // Remove TableID, RecordNo, DocType, LineNo, ID
            FileName := StrSubstNo('%1', StrJoin(FileNameParts, '_')); // Join remaining parts
            // Verify the record exists
            RecRef.Open(TableID);
            if not RecRef.GetBySystemId(RecordNo) then // Adjust based on primary key
                Error(RecordNotFoundErr, RecordNo, TableID);
            RecRef.Close();
            // Extract the file content
            Clear(EntryOutStream);
            Clear(EntryInStream);
            TempBlob.CreateOutStream(EntryOutStream);
            if not DataCompression.ExtractEntry(EntryListKey, EntryOutStream) then
                Error('Failed to extract file "%1".', FileName);
            TempBlob.CreateInStream(EntryInStream);
            // Check for existing attachment
            if DocAttach.Get(TableID, RecordNo, DocType, LineNo, ID) then
                DocAttach.Delete(true); // Optionally update instead of delete
            // Create new document attachment
            DocAttach.Init();
            DocAttach.Validate("Table ID", TableID);
            DocAttach.Validate("No.", RecordNo);
            DocAttach.Validate("Document Type", DocType);
            DocAttach.Validate("Line No.", LineNo);
            DocAttach.ID := ID;
            DocAttach.Validate("File Name", FileName);
            DocAttach.Validate("File Extension", FileExtension);
            if not DocAttach."Document Reference ID".ImportStream(EntryInStream, FileName) then
                Error('Failed to import file "%1" into Document Reference ID.', FileName);
            DocAttach.Insert(true);
            FileCount += 1;
        end;
        // Close the zip file
        DataCompression.CloseZipArchive();
        if FileCount > 0 then
            Message(ImportedMsg, FileCount);
    end;
    local procedure StrJoin(List: List of [Text]; Delimiter: Text): Text
    var
        Result: Text;
        Item: Text;
    begin
        foreach Item in List do begin
            if Result = '' then
                Result := Item
            else
                Result += Delimiter + Item;
        end;
        exit(Result);
    end;
  • Suggested answer
    Khushbu Rajvi. Profile Picture
    17,377 Super User 2025 Season 1 on at
  • Suggested answer
    YUN ZHU Profile Picture
    84,325 Super User 2025 Season 1 on at
    Insert multiples file from zip
    Add another example, hope it can help you as well.
    Dynamics 365 Business Central: Import Multiple Customer Pictures (Customization)
     
    Thanks.
    ZHU
  • Verified answer
    Gerardo Rentería García Profile Picture
    19,744 Most Valuable Professional on at
  • Suggested answer
    Saif Ali Sabri Profile Picture
    2,218 Super User 2025 Season 1 on at
    Insert multiples file from zip
    The issue you're facing — PDFs opening with random file details or blank pages — typically indicates that the binary stream (InStream) being passed to the attachment import function is corrupted, truncated, or not properly reset/repositioned.
    Here’s a deep technical breakdown and a solution to address this issue in your ImportAttachmentsFromZip procedure:

    Root Cause
    When using TempBlob.CreateOutStream() followed by TempBlob.CreateInStream(), if the OutStream is still active or data isn't properly flushed/rewound before creating the InStream, it results in:
    • Incomplete binary data.
    • Corrupted or unreadable PDF content.
    This is common with PDF files because their binary structure is sensitive to corruption — even minor issues can make them unreadable or appear blank.

    🛠️ Solution
    Step-by-Step Fix
    Replace your extraction and stream handling section with this improved version:
    🔧 Replace this block:
    al
    CopyEdit
    Clear(EntryOutStream);
    Clear(EntryInStream);
    TempBlob.CreateOutStream(EntryOutStream);
    if not DataCompression.ExtractEntry(EntryListKey, EntryOutStream) then
        Error('Failed to extract file "%1".', FileName);
    TempBlob.CreateInStream(EntryInStream);
    With this revised block:
    al
    CopyEdit
    TempBlob.CreateOutStream(EntryOutStream);
    if not DataCompression.ExtractEntry(EntryListKey, EntryOutStream) then
        Error('Failed to extract file "%1".', FileName);

    // Flush the OutStream (especially important in some environments)
    EntryOutStream := null;

    // Now create InStream from TempBlob content
    TempBlob.CreateInStream(EntryInStream);
    By nullifying EntryOutStream before creating EntryInStream, you're ensuring the data is fully flushed and ready for reading. This step resolves 99% of blank or corrupted PDF issues when dealing with streams in AL.

    Bonus Validation (Optional)
    If you want to validate the content is really a PDF, you can add a basic check using the PDF header (first bytes are %PDF):
    al
    CopyEdit
    var
        FirstBytes: Text[4];
    begin
        EntryInStream.ReadText(FirstBytes, 4);
        if FirstBytes <> '%PDF' then
            Error('File "%1" is not a valid PDF.', FileName);
        EntryInStream.Position := 0; // Reset position after read
    end;

    Final Notes
    • The logic of splitting file name and mapping to TableID, RecordNo, etc., seems correct.
    • Make sure that DocAttach."Document Reference ID".ImportStream() supports the full stream and doesn't truncate it.
    • Consider logging or auditing any failed imports for troubleshooting.

    Conclusion
    The core issue lies in how the streams are handled post extraction. Ensure the OutStream is finalized before creating InStream. Use the revised block above and your PDF attachments should import and display correctly.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Jainam Kothari – Community Spotlight

We are honored to recognize Jainam Kothari as our June 2025 Community…

Congratulations to the May Top 10 Community Leaders!

These are the community rock stars!

Announcing the Engage with the Community forum!

This forum is your space to connect, share, and grow!

Leaderboard > Small and medium business | Business Central, NAV, RMS

#1
Sohail Ahmed Profile Picture

Sohail Ahmed 1,452

#2
YUN ZHU Profile Picture

YUN ZHU 1,313 Super User 2025 Season 1

#3
Gerardo Rentería García Profile Picture

Gerardo Rentería Ga... 1,083 Most Valuable Professional

Featured topics

Product updates

Dynamics 365 release plans