トップ回答者
DataTableの内容をXmlWriterで保存するとファイルのテキストの末尾がおかしくなる

質問
-
VB.NETで作成したソフトにてDataTableのデータをxmlファイルにて共有フォルダに保存し、その内容を複数台のPCからRead/Writeしたいと考えています。
そのために処理A 処理Bを作成して保存を行うと出力結果①のように
xmlの末尾が重複するような表示になる
という問題が稀に発生し、その後そのファイルを読もうとすると
ルートレベルのデータが無効です
というエラーが表示されます。
FileStreamにて競合が起きないように制限しているつもりでしたが、書込み制御が上手く実施できていないのでしょうか?
対策方法を教えて頂ければ幸いです。
xmlの出力結果①(常時このようになるわけではない)
<?xml version="1.0" encoding="utf-8"?> <NewDataSet> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="テーブル" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="テーブル"> <xs:complexType> <xs:sequence> <xs:element name="列" type="xs:string" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:dateTime" minOccurs="0" /> <xs:element name="列" type="xs:string" minOccurs="0" /> <xs:element name="列" type="xs:string" minOccurs="0" /> <xs:element name="列d" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <テーブル> <列>DATA_A</列> <列>2018-04-06T12:30:00+09:00</列> <列>0</列> <列></列> <列d></列d> </テーブル> </NewDataSet>> <列d></列d> </テーブル> </NewDataSet>
処理A
Protected Friend _Lines As New List(Of cls_Line)
''' <summary>ラインクラス</summary>
Public Class cls_Line
Protected Friend fs As System.IO.FileStream = Nothing'---クラス処理---
End Class
Public Function Write_ToFile(LineCode As String) As Boolean Dim Result As Boolean = False If System.IO.Exists(ファイルパス) = True Then
Dim IsAlreadyOpened As Boolean = True
Dim IsOpenSuccess As Boolean = True
If LineIndex(LineCode) >= 0 Then
With Line(LineCode)
If .fs Is Nothing OrElse .fs.CanWrite = False ThenIsAlreadyOpened = False IsOpenSuccess = FileLock() End If If IsOpenSuccess = False Then '---エラー処理--- Result = False Else SyncLock .fs Try XmlFile_Write(.fs, .Table) If IsAlreadyOpened = False AndAlso .fs IsNot Nothing Then FileUnLock() End If Result = True Catch ex As Exception '---エラー処理--- End Try End SyncLock
End If
End With
Else
SaveErrorLog(MethodData, "No LineCode: " & LineCode)
End IfElse '---エラー処理--- End If Return Result End Function
''' <summary>ファイルをロック</summary>
Line(0).fs = System.IO.File.Open(ファイルパス, IO.FileMode.OpenOrCreate, IO.FileAccess.ReadWrite, IO.FileShare.None)
Public Function FileLock() As Boolean
Dim Result As Boolean = False
Try
Result = True
Catch ex As Exception
Result = False
End Try
Return Result
End Function
''' <summary>ファイルをアンロック</summary>
Public Function FileUnLock() As Boolean
Dim Result As Boolean = False
Try
Line(0).fs.Close()
Result = True
Catch ex As Exception
Result = False
End Try
Return Result
End Function
処理B
Public Function XmlFile_Write(ByRef fs As System.IO.FileStream, ByRef SaveTable As DataTable) As Boolean Dim Result As Boolean = False Try If fs Is Nothing OrElse SaveTable Is Nothing Then '---エラー処理--- Else Dim settings As New XmlWriterSettings() settings.Indent = True settings.Encoding = System.Text.Encoding.UTF8 Using writer As Xml.XmlWriter = XmlWriter.Create(fs, settings) SaveTable.WriteXml(writer, XmlWriteMode.WriteSchema) Result = True End Using End If Catch ex As Exception '---エラー処理--- End Try Return Result End Function
- 編集済み 2kensystemteam 2018年4月6日 5:15
回答
-
OpenOrCreate: 存在する場合に、オペレーティング システムでファイルを開くことを指定します。それ以外の場合、新しいファイルを作成する必要があります。
Create: オペレーティング システムが新しいファイル作成することを指定します。 ファイルが既に存在する場合は上書きされます。
たぶんCreateが望む動作でしょうね。
- 回答としてマーク 2kensystemteam 2018年4月6日 12:50
すべての返信
-
OpenOrCreate: 存在する場合に、オペレーティング システムでファイルを開くことを指定します。それ以外の場合、新しいファイルを作成する必要があります。
Create: オペレーティング システムが新しいファイル作成することを指定します。 ファイルが既に存在する場合は上書きされます。
たぶんCreateが望む動作でしょうね。
- 回答としてマーク 2kensystemteam 2018年4月6日 12:50
-
返信が遅くなり申し訳ありません。
なるほど
OpenPrCreateでは一度ファイルを開いてからWriteしていた為、元のテキストより短いとこのような形になってしまっていたのですか。
理解しきらずに使ってしまっていました。
ご指摘の通りに直しましたら解決致しました。
大変助かりました。
もう少し勉強してから関数を利用するようにしたいと思います。
皆様有難うございました。
- 編集済み 2kensystemteam 2018年4月6日 12:57