none
DataTableの内容をXmlWriterで保存するとファイルのテキストの末尾がおかしくなる RRS feed

  • 質問


  • 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 Then

    IsAlreadyOpened = 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 If

    Else '---エラー処理--- End If Return Result End Function

      ''' <summary>ファイルをロック</summary>
      Public Function FileLock() As Boolean
        Dim Result As Boolean = False

        Try

          Line(0).fs = System.IO.File.Open(ファイルパス, IO.FileMode.OpenOrCreate, IO.FileAccess.ReadWrite, IO.FileShare.None)


          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



    2018年4月6日 5:11

回答

  • FileMode.OpenOrCreateでFileStreamを作っているようなので、既存のXMLファイルよりも短い内容を書き込んで、既存のデータが後ろに残っていた、ということではないでしょうか。
    • 回答の候補に設定 佐祐理 2018年4月6日 13:58
    • 回答としてマーク 2kensystemteam 2018年4月8日 23:16
    2018年4月6日 5:58
  • FileMode 列挙型より

    OpenOrCreate: 存在する場合に、オペレーティング システムでファイルを開くことを指定します。それ以外の場合、新しいファイルを作成する必要があります。

    Create: オペレーティング システムが新しいファイル作成することを指定します。 ファイルが既に存在する場合は上書きされます。

    たぶんCreateが望む動作でしょうね。

    2018年4月6日 6:09

すべての返信

  • FileMode.OpenOrCreateでFileStreamを作っているようなので、既存のXMLファイルよりも短い内容を書き込んで、既存のデータが後ろに残っていた、ということではないでしょうか。
    • 回答の候補に設定 佐祐理 2018年4月6日 13:58
    • 回答としてマーク 2kensystemteam 2018年4月8日 23:16
    2018年4月6日 5:58
  • FileMode 列挙型より

    OpenOrCreate: 存在する場合に、オペレーティング システムでファイルを開くことを指定します。それ以外の場合、新しいファイルを作成する必要があります。

    Create: オペレーティング システムが新しいファイル作成することを指定します。 ファイルが既に存在する場合は上書きされます。

    たぶんCreateが望む動作でしょうね。

    2018年4月6日 6:09
  • 返信が遅くなり申し訳ありません。

    なるほど

    OpenPrCreateでは一度ファイルを開いてからWriteしていた為、元のテキストより短いとこのような形になってしまっていたのですか。

    理解しきらずに使ってしまっていました。

    ご指摘の通りに直しましたら解決致しました。

    大変助かりました。

    もう少し勉強してから関数を利用するようにしたいと思います。

    皆様有難うございました。


    2018年4月6日 12:55