#概要
Documents.Open(), Document.Close()を利用して既存文書を開いて閉じます。
そのほかのテーマは以下です。
#利用する文書について
Word文書が安全かどうか保証できないので適宜用意してください。
そこそこ量があり、章・節を使った構造的文書(例えば、設計書・仕様書)がほしかったので、ここではローカルにあった(Visual Studioインストールで入った)「C# Language Specification Version 5.0」(CSharp Language Specification.docx)のコピーを利用しています。
#今回利用するWordオブジェクト
オブジェクト名 | プロパティ/メソッド | 説明 | リンク |
---|---|---|---|
Documents | - | Documentのコレクション | msdn |
Open() | 文書を開く | msdn | |
Document | - | Documents内の1つの文書 | msdn |
Close() | 指定した文書を閉じる | msdn |
#コード
qtconsoleの確認結果を示していきますが、前回同様テンプレ的な処理は省略します。
↓の「★なんらかの処理★」部分に記述しているイメージで読んでください。
import win32com.client
#Wordを起動する : Applicationオブジェクトを生成する
Application=win32com.client.Dispatch("Word.Application")
#Wordを画面表示する : VisibleプロパティをTrueにする
Application.Visible=True
★なんらかの処理★
#Wordを終了する : Quitメソッドを呼ぶ
Application.Quit()
##文書を開く
Documents.Open()を利用して、C:\tmp\CSharp Language Specification.docxにあるファイルを開きます。ファイル名を絶対パスで指定して開いてみます。
In [54]: doc=Application.Documents.Open(r"C:\tmp\CSharp Language Specification.docx")
pathlibを利用して相対パス的に開いてみます。
In [57]: import pathlib
In [58]: cd c:\tmp
c:\tmp
In [59]: p=pathlib.Path(".").joinpath("CSharp Language Specification.docx")
In [60]: p.resolve()
Out[60]: WindowsPath('C:/tmp/CSharp Language Specification.docx')
In [61]: doc=Application.Documents.Open(str(p.resolve()))
##文書を読み取り専用で開く
Documents.Open()を読み取り専用で開いてみます。引数のReadOnlyを利用します。
名前付き引数に気を付けるも参照ください。
式 . Open( FileName, ConfirmConversions, ReadOnly , ・・・
|名前|必須 / 省略可能|説明|
|:---|:---|:---|:---|
|ReadOnly|省略可能|True:読み取り専用|
In [71] doc=Application.Documents.Open(FileName=r"C:\tmp\CSharp Language Specification.docx", ConfirmConversions=False, ReadOnly=True)
In [72] doc = Application.Documents.Open(r"C:\tmp\CSharp Language Specification.docx",False,True)
In [73] doc=Application.Documents.Open(r"C:\tmp\CSharp Language Specification.docx",None,True)
##文書を閉じる
docで受け取ったDocumentオブジェクト参照からClose()メソッドを呼ぶだけです。
In [74]: doc.Close()
ちなみに、Documentオブジェクトをdocで受け取るのはMustではないです。
後述しますが、Documentオブジェクトは名前付きオブジェクトなので、名前(Name, FullNameと同じ文字列)でコレクションから取りだせます。
#Open()で開いてNameを確認する
In [88]: Application.Documents.Open(r"C:\tmp\CSharp Language Specification.docx").Name
Out[88]: 'CSharp Language Specification.docx'
#Nameと同じ文字列を使って、Documentsコレクションからオブジェクトを取り出し、Close()を呼ぶ
In [89]: Application.Documents("CSharp Language Specification.docx").Close()
#Open()で開いてFullNameを確認する
In [90]: Application.Documents.Open(r"C:\tmp\CSharp Language Specification.docx").FullName
Out[90]: 'C:\\tmp\\CSharp Language Specification.docx'
#FullNameと同じ文字列を使って、Documentsコレクションからオブジェクトを取り出し、Close()を呼ぶ
In [91]: Application.Documents("C:\\tmp\\CSharp Language Specification.docx").Close()
##変更を保存せずに文書を閉じる
Document.Close()を使って、変更を保存せずに文書を閉じてみます。
引数のSaveChangesの指定に定数(wdDoNotSaveChangesなど)を利用できますが、事前準備が必要なので、今回は直値で指定します。
式 . Close( SaveChanges, OriginalFormat, RouteDocument )
|名前|必須 / 省略可能|説明|
|:---|:---|:---|:---|
|SaveChanges|省略可能|文書の保存方法を指定。使用できる定数は、WdSaveOptions列挙のいずれか|
|名前|値|説明|
|:---|:---|:---|:---|
|wdDoNotSaveChanges|0|保留中の変更を保存しない|
|wdPromptToSaveChanges|-2|保留中の変更を保存するかどうかユーザーに確認|
|wdSaveChanges|-1|保留中の変更をユーザーに確認しないで自動的に保存|
引数なしのClose()と挙動の違いを見るために、文書を読み取り専用で開きます。
#文書を読み取り専用で開く : Open(ReadOnly=True)を呼ぶ
In [121]: doc=Application.Documents.Open(FileName=r"C:\tmp\CSharp Language Specification.docx", ConfirmConversions=False, ReadOnly=True)
手で適当に変更を加えます。
Close()を引数なしで呼びます。
#文書を閉じる : Close()を引数なしで呼ぶ
In [121]: doc.Close()
読み取り専用のファイルに変更を加えてしまったので、ファイル名を変更するようにダイアログができてしまいます。
キャンセルしてダイアログを抜けると以下の例外が発生します。
In [122]: doc.Close()
---------------------------------------------------------------------------
com_error Traceback (most recent call last)
<ipython-input-122-f62a2a61dece> in <module>()
----> 1 doc.Close()
com_error: (-2147352567, '例外が発生しました。', (0, 'Microsoft Word', 'このファイルは読み取り専用なので上書き保存できません。\n変更内容を保持するには、文書を別の名前で保存するか、別の場所に保存する必要があります。\r (C:\\...\\CSharp Language Specification....)', 'wdmain11.chm', 24635, -2146823133), None)
変更を保存せずに文書を閉じるために、Close(SaveChanges=0)を呼び出してみます。
#変更を保存せずに文書を閉じる : Close(SaveChanges=0)を呼び出す。
In [123]: doc.Close(SaveChanges=0)
今度は、何事もなく閉じることができます。
念のためもう一回開きます。
In [124]: doc=Application.Documents.Open(FileName=r"C:\tmp\CSharp Language Specification.docx", ConfirmConversions=False, ReadOnly=True)
先ほど加えた変更が反映されてないことが確認できました。
#コレクションと名前付きオブジェクトについて
##Wordのコレクションについて
Wordのコレクションの各要素には、Documents(1)、Documents(2)、・・・と丸括弧でアクセスします。以下に注意が必要です
- 角括弧ではないこと
- nは1から始まること
- Add()、Close()などの呼び出しやGUI操作(e.g.windowのクローズ操作)でコレクションの位置が変わる
名前付きオブジェクト(Nameプロパティを持っているオブジェクト)は、数値インデックス的なアクセスに加えて、「名前」(Nameプロパティ, FullNameプロパティと同じ文字列)を使ってアクセスできます。
前回、Tasksコレクションで暗黙的に使っています。(TaskオブジェクトにNameプロパティがある)
#名前付き引数に気を付ける
pywin32だと 名前付き引数を使っても途中の引数が省略できない ようです。(msdnの仕様を読んで位置を把握しないといけない)
式 . Open( FileName, ConfirmConversions, ReadOnly , ・・・
|名前|必須 / 省略可能|説明|
|:---|:---|:---|:---|
|FileName|必須|文書の名前/パス|
|ConfirmConversions|省略可能|True:Word 形式ではない場合、ファイルの変換ダイアログを表示|
|ReadOnly|省略可能|True:読み取り専用|
ReadOlyの場合、FileNameとReadOlyの間にConfirmConversionsがあるので、ConfirmConversionsに何らかの値(True, False, None)を渡す必要があります。msdnで省略可能となっている部分は 本当に省略するのではなくNoneを渡す と既定のデフォルトで動いてくれます。
VBAだとこのあたりいい感じに処理されているので以下のようなサンプルコードがよくあります。
Sub OpenDoc()
Documents.Open FileName:="C:\MyFiles\MyDoc.doc", ReadOnly:=True
End Sub
再実装する場合は、明示的に名前付きで設定された引数の間に隠されている引数がないか、調査する必要があります。上記の例では、ConfirmConversionsがその隠された引数です。
VBScriptは、「名前付き引数自体をサポートしてない」+「使わない引数に何も設定しなくてよい」(下記の例参照)ので、こちらも再実装する際に気を付けるポイントになります。おそらく多くのケースNoneを設定すればなんとかなると思います。
例:
Officeファイルを読み取り専用で開くスクリプト - motoraku’s gists
'■読み取り専用で開く
Call objApp.Documents.Open(strFileName,,True)
#関連
Python(pywin32)でWordを操作する[1] - Wordオブジェクトモデル
Python(pywin32)でWordを操作する[2] - Wordを起動/終了する
Python(pywin32)でWordを操作する[3] - 新規ドキュメント作成
Python(pywin32)でWordを操作する[4] - 文字列を入力/取得/削除する
Python(pywin32)でWordを操作する[5] - ドキュメントをファイルに保存する、Wordのオプション変更
Python(pywin32)でWordを操作する[6] - 特定のタイトルが付いているウィンドウの操作
Python(pywin32)でWordを操作する[7] - 既存文書を開く/閉じる(Documents.Open(), Document.Close())
Python(pywin32)でWordを操作する[8] - 段落単位の文字列取得, 統計(ページ数, 段落数,etc)取得
#参考