ApexでファイルをZipにまとめてレコードへ残す実装
複数のファイルを1件ずつダウンロードするのは手間です。ApexのCompression名前空間で1つのZipにまとめ、レコードのファイルとして残す実装を説明します。
なぜまとめて圧縮するのか
取引先に何十件もファイルが添付されていると、1件ずつ開いてダウンロードするのは手間です。複数のファイルを1つのZipにまとめれば、ダウンロードは1回で済みます。
Apexには圧縮・展開のためのCompression名前空間が用意されています。Zipを作る処理を自分で書く必要はありません。
対象のファイルをFilesで管理する
添付ファイルはAttachmentではなくContentVersion・ContentDocumentLinkで管理します。Attachmentは旧世代のオブジェクトで、新しく作る仕組みでは使いません。
取引先レコードを開く
Filesの関連リストを表示します。
ファイルをアップロードする
「ファイルを追加」から検証用のファイルを2〜3件アップロードします。
関連付けを確認する
アップロードしたファイルが、取引先のFilesリストに表示されることを確認します。
Apexでまとめて圧縮する
取引先に紐づくファイルの最新バージョンを取得し、Compression.ZipWriterでまとめます。
List<ContentDocumentLink> links = [ SELECT ContentDocumentId FROM ContentDocumentLink WHERE LinkedEntityId = :accountId ]; Set<Id> docIds = new Set<Id>(); for (ContentDocumentLink link : links) { docIds.add(link.ContentDocumentId); } List<ContentVersion> versions = [ SELECT PathOnClient, VersionData FROM ContentVersion WHERE ContentDocumentId IN :docIds AND IsLatest = true ]; Compression.ZipWriter writer = new Compression.ZipWriter(); for (ContentVersion version : versions) { writer.addEntry(version.PathOnClient, version.VersionData); } Blob zipData = writer.getArchive();
取引先に添付された最新バージョンのファイルを1つのZipにまとめます。読み取りだけです。
ここでいうdocIdsとversionsは、いったんヒープに全ファイルを載せます。ファイルが大きい、または件数が多いときは、次の見出しの上限に注意します。
圧縮したファイルをレコードに残す
作ったBlobを、新しいContentVersionとして保存します。FirstPublishLocationIdに取引先のIDを指定すると、ファイルの関連付け(ContentDocumentLink)が自動でできます。
ContentVersion archive = new ContentVersion(); archive.Title = 'attachments.zip'; archive.PathOnClient = 'attachments.zip'; archive.VersionData = zipData; archive.FirstPublishLocationId = accountId; insert archive;
Zipを新しいファイルとして保存し、取引先へ自動で関連付けます。
保存後は、取引先のFilesの関連リストにattachments.zipが現れます。ダウンロードは、通常のファイルと同じ操作で行えます。別のダウンロード用URLを自分で組み立てる必要はありません。
Documentに保存し、/servlet/servlet.FileDownload?file=...というURLへ遷移してダウンロードさせるものが目立ちます。Filesの関連リストからダウンロードする、上の形に置き換えます。画面から呼び出す
取引先のレコードページから実行できるように、Visualforceページとコントローラ拡張を用意します。
fileCompressionController.cls
public with sharing class fileCompressionController { private final Id accountId; public fileCompressionController(ApexPages.StandardController stdController) { this.accountId = stdController.getId(); } public PageReference compressFiles() { List<ContentDocumentLink> links = [ SELECT ContentDocumentId FROM ContentDocumentLink WHERE LinkedEntityId = :accountId ]; Set<Id> docIds = new Set<Id>(); for (ContentDocumentLink link : links) { docIds.add(link.ContentDocumentId); } List<ContentVersion> versions = [ SELECT PathOnClient, VersionData FROM ContentVersion WHERE ContentDocumentId IN :docIds AND IsLatest = true ]; Compression.ZipWriter writer = new Compression.ZipWriter(); for (ContentVersion version : versions) { writer.addEntry(version.PathOnClient, version.VersionData); } ContentVersion archive = new ContentVersion(); archive.Title = 'attachments.zip'; archive.PathOnClient = 'attachments.zip'; archive.VersionData = writer.getArchive(); archive.FirstPublishLocationId = accountId; insert archive; return null; } }
取引先のIDを受け取り、Zip作成と保存をまとめて行います。
fileCompression.page
<apex:page standardController="Account" extensions="fileCompressionController"> <apex:form> <apex:pageBlock title="ファイルをまとめて圧縮"> <apex:pageBlockButtons location="bottom"> <apex:commandButton action="{!compressFiles}" value="圧縮する" reRender="none"/> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page>
画面には確認メッセージだけを表示し、ボタンで圧縮処理を呼び出します。
クラスのアクセス権限を許可する
Apexクラスは、既定では管理者以外に実行権限がありません。使う人に権限セットで許可します。
権限セットを開く
設定の権限セットから、対象ユーザーに割り当てているものを開きます。
Apexクラスのアクセスを開く
「Apexクラスのアクセス」を編集します。
fileCompressionControllerを有効にする
有効なApexクラスのリストへ追加して保存します。
ここで間違えやすい
| 間違い | 何が起きるか |
|---|---|
Attachmentのまま作る | 新規の実装では使いません。ContentVersionに置き換えます |
| ファイルを1件ずつヒープに載せ続ける | 同期実行のヒープ上限(6MB)に当たります。件数や合計サイズが多いときは非同期処理(12MB)に分けます |
ContentDocumentLinkを別途insertする | FirstPublishLocationIdを指定すれば自動で作られます。二重に作ると関連付けが重複します |
| クラスへのアクセス権限を付与し忘れる | ボタンを押すと、権限エラーになります |
確認した環境
- 2026年9月/Salesforce Summer '26(APIバージョン67.0)時点の公式リファレンスで、
Compression名前空間とContentVersionの項目を確認しています
まとめ
- 複数ファイルは
Compression.ZipWriterで1つのZipにまとめられます - 添付ファイルの管理は
AttachmentではなくContentVersion・ContentDocumentLinkを使います FirstPublishLocationIdを指定してinsertすると、レコードへの関連付けが自動でできます- ダウンロードはFilesの関連リストから行います。独自のダウンロードURLは不要です
- ヒープ上限は同期処理6MB・非同期処理12MBです。ファイルが多いときは非同期処理に分けます
- Apexクラスの実行には権限セットでの許可が要ります
参考:当時の画面
記事を最初に書いた当時の画面です。いまの手順と違うところは、各画像の説明に書いています。
Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。