Visualforceでテキストファイルを出力する2つの方法
取引先の詳細画面のボタンから、取引先名をテキストファイルにして保存します。ContentVersionを使う理由、apex:pageのcontentTypeで直接ダウンロードさせる方法との違い、文字コードの扱い、出力データが増えたときのヒープ上限まで説明します。
この実装が作るもの
取引先の詳細画面にボタンを置き、押すと取引先名をテキストファイルにして、その取引先に添付します。ファイルはContentVersionとして作り、ContentDocumentLinkで取引先とひもづけます。Attachmentオブジェクトは使いません。Salesforce Filesの仕組みに沿った、いまも通る書き方です。
Visualforceページ
<apex:page showQuickActionVfHeader="false" apiVersion="67.0" standardController="Account" extensions="TextFileOutputSampleController"> <apex:form> <apex:pageBlock title="テキストファイル作成画面"> <apex:pageBlockTable title="取引先" value="{!acc}" var="acc"> <apex:column headerValue="取引先名"> <apex:outputField value="{!acc.Name}" /> </apex:column> </apex:pageBlockTable> <apex:pageBlockButtons location="bottom"> <div style="width:250px; text-align:center;"> <apex:commandButton action="{!createFile}" value="テキストファイル作成" /> <apex:commandButton action="{!cancel}" value="キャンセル" /> </div> </apex:pageBlockButtons> </apex:pageBlock> </apex:form> </apex:page>
取引先の標準コントローラーを拡張し、ボタンでテキストファイルを作成します。
Apexクラス
public with sharing class TextFileOutputSampleController { public Account acc {get; set;} private Id accId; public TextFileOutputSampleController(ApexPages.StandardController stdController) { this.acc = (Account)stdController.getRecord(); this.accId = this.acc.Id; getRecord(); } private void getRecord() { this.acc = [SELECT Id, Name FROM Account WHERE Id = :this.accId LIMIT 1]; } public PageReference createFile() { String fileContent = ''; fileContent += this.acc.Name; Savepoint sp = Database.setSavepoint(); try { ContentVersion cv = new ContentVersion(); cv.Title = 'accText.txt'; cv.PathOnClient = 'accText.txt'; cv.VersionData = Blob.valueOf(fileContent); cv.ContentLocation = 'S'; insert cv; ContentDocumentLink cdLink = new ContentDocumentLink(); cdLink.ContentDocumentId = [SELECT ContentDocumentId FROM ContentVersion WHERE Id = :cv.Id].ContentDocumentId; cdLink.LinkedEntityId = this.accId; cdLink.ShareType = 'V'; insert cdLink; return new PageReference('/' + accId); } catch (DmlException e) { System.debug('The following exception has occurred: ' + e.getMessage()); Database.rollback(sp); return null; } } public PageReference cancel() { return new PageReference('/' + this.accId); } }
取引先名からテキストファイルを作り、ContentVersionとして取引先へ添付します。
ContentVersionをContentDocumentIdを指定せずに新規作成すると、対応するContentDocumentが自動的に作られます。直後にContentVersionをIdで引き直してContentDocumentIdを取り出しているのは、この自動生成された値を使ってContentDocumentLinkを作るためです。
apex:pageのcontentTypeで直接ダウンロードさせる方法との違い
この実装はファイルを取引先の「ファイル」関連リストへ保存するもので、ボタンを押した瞬間にブラウザがダウンロードを始めるわけではありません。ブラウザに直接ダウンロードさせたいだけなら、apex:pageのcontentType属性でページ自体をテキストとして出力する方法もあります。
| ContentVersionで保存(この記事のコード) | apex:pageのcontentTypeで直接出力 | |
|---|---|---|
| 出力先 | 取引先に添付されたSalesforceのファイル | ブラウザのダウンロード |
| 保存後の扱い | ファイル関連リストからいつでも参照できる | ページを開くたびに出力するだけで、レコードとしては残らない |
| 向いている場面 | 取引先に証跡として残したいとき | その場でファイルを受け取れればよいとき |
contentType属性はMIMEタイプの指定だけで、文字コード(charset)を切り替える属性は用意されていません。Visualforceページ自体は既定でUTF-8として出力されます。Shift_JISなど他の文字コードでダウンロードさせたい場合、apex:pageの属性だけでは対応できません。出力データが増えたときの注意
このコードは取引先名1件分をfileContentに連結するだけなので問題になりませんが、複数レコードの値を1つの文字列にまとめて出力するように広げると、fileContentに連結される文字列がどんどん増えていきます。同期処理のApexが使えるヒープサイズは6MBまでです。大きなファイルを作る処理をBatch Apexに移すと、ヒープサイズの上限は12MBに広がります。1つの巨大な文字列を作り続けるのではなく、行ごとのList<String>を作ってString.join()でまとめるなど、ヒープの使い方にも注意してください。
ここで間違えやすい
| 間違い | 何が起きるか |
|---|---|
Attachmentオブジェクトへファイルを保存する | 添付ファイルの新しい保存先としては推奨されません。ContentVersionとContentDocumentLinkを使います |
contentTypeだけでUTF-8以外の文字コードにしようとする | 文字コードを切り替える属性が無いため、意図通りになりません |
ContentDocumentLinkのShareTypeを確認せずに使う | 取引先側からファイルを見られる権限が想定と変わります |
| 出力データが増えても1つの文字列に連結し続ける | 同期処理のヒープサイズ(6MB)に近づきます |
確認した環境
- 2026年9月/Salesforce Summer '26(APIバージョン67.0)時点の公式ドキュメントで、ContentVersionの挙動、apex:pageのcontentType属性、Apexのヒープサイズの上限を確認しています
- コードはAPIバージョン67.0で書いています
まとめ
- 取引先へファイルを添付するなら、
AttachmentではなくContentVersionとContentDocumentLinkを使います ContentDocumentIdを指定せずにContentVersionを新規作成すると、対応するContentDocumentが自動的に作られます- ブラウザへその場でダウンロードさせたいだけなら、
apex:pageのcontentType属性で直接出力する方法もあります contentType属性に文字コードを切り替える仕組みはなく、Visualforceページは既定でUTF-8として出力されます- 出力データが増える処理では、同期処理のヒープサイズ上限(6MB)を意識し、大きな処理はBatch Apexへ移します
Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。