/// <summary> /// Opens the file in write mode and allows appending items to it. The filepointer is set to the end of the file. /// </summary> /// <param name="path">The path of the file. </param> /// <param name="elementsToValidate">The elements of the ItemDescription to validate. /// <see cref="ItemDescriptionElements"/> for details. </param> /// <returns>. </returns> /// <exception cref="ArgumentException">If path is null.</exception> public static TeaFile <T> Append(string path, ItemDescriptionElements elementsToValidate = ItemDescriptionElements.All) { if (path == null) { throw new ArgumentNullException("path"); } Stream headerStream = null; Stream stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read); try { headerStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); return(Append(stream, true, headerStream, elementsToValidate)); } catch (Exception) { stream.Dispose(); throw; } finally { if (headerStream != null) { headerStream.Dispose(); } } }
static TeaFile <T> OpenRead(Stream stream, bool ownsStream, ItemDescriptionElements elementsToValidate) { var tf = new TeaFile <T>(); try { tf.core = new TeaFileCore(stream, ownsStream); tf.buffer = new SafeBuffer <T>(stream); tf.core.ReadHeader(); // reflecting the current type incurs some cost, so we do it only if we are asked to consider // current item layout to check it against to layout described in the file ItemDescription accessorDescription = null; if (elementsToValidate != ItemDescriptionElements.None) { accessorDescription = ItemDescription.FromAnalysis <T>(); } tf.core.IsAccessibleWith(accessorDescription, elementsToValidate); return(tf); } catch (Exception) { tf.Dispose(); throw; } }
/// <summary>Opens a TeFile in write mode. </summary> /// <exception cref="ArgumentNullException"><paramref name="stream"/> is null. </exception> /// <param name="stream">The underlying storage media. </param> /// <param name="elementsToValidate">Elements of the ItemDescription to be checked. /// <see cref="ItemDescriptionElements"/> for details. </param> /// <returns>A TeaFile, open in write mode. </returns> public static TeaFile <T> OpenWrite(Stream stream, ItemDescriptionElements elementsToValidate = ItemDescriptionElements.All) { if (stream == null) { throw new ArgumentNullException("stream"); } return(OpenWrite(stream, false, elementsToValidate)); }
/// <summary>Opens a TeaFile in read only mode. </summary> /// <exception cref="ArgumentNullException">Thrown when path is null. </exception> /// <param name="path">The path of the file. </param> /// <param name="elementsToValidate">Elements of the ItemDescription of <typeparamref name="T"/> compared against hose inside thefile. /// <see cref="ItemDescriptionElements"/> for details. </param> /// <returns>The file, open for reading. </returns> public static TeaFile <T> OpenRead(string path, ItemDescriptionElements elementsToValidate = ItemDescriptionElements.All) { if (path == null) { throw new ArgumentNullException("path"); } Stream stream = new FileStream(path, FileMode.Open); return(OpenRead(stream, true, elementsToValidate)); }
public void IsAccessibleWith(ItemDescription accessorDescription, ItemDescriptionElements elements) { // without descriptions in the file we cannot check anything. No warning will be issued in such case, // the user is responsible to check that files have descriptions if desired. if (this.Description == null) { return; } if (this.Description.ItemDescription == null) { return; } var fileDescription = this.Description.ItemDescription; fileDescription.IsAccessibleWith(accessorDescription, elements); }
/// <summary>Opens a TeFile in write mode. </summary> /// <exception cref="ArgumentNullException">Path is null. </exception> /// <param name="path">The path of the file. </param> /// <param name="elementsToValidate">Elements of the ItemDescription to be checked. /// <see cref="ItemDescriptionElements"/> for details. </param> /// <returns>A TeaFile in write mode. </returns> /// <remarks><see cref="OpenRead(string,TeaTime.ItemDescriptionElements)"/> about the <paramref name="elementsToValidate"/> parameter.</remarks> public static TeaFile <T> OpenWrite(string path, ItemDescriptionElements elementsToValidate = ItemDescriptionElements.All) { if (path == null) { throw new ArgumentNullException("path"); } Stream stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); try { return(OpenWrite(stream, true, elementsToValidate)); } catch { stream.Dispose(); throw; } }
static TeaFile <T> OpenWrite(Stream stream, bool ownsStream, ItemDescriptionElements elementsToValidate) { var tf = new TeaFile <T>(); try { tf.buffer = new SafeBuffer <T>(stream); tf.core = new TeaFileCore(stream, ownsStream); tf.core.ReadHeader(); tf.core.IsAccessibleWith(ItemDescription.FromAnalysis <T>(), elementsToValidate); // filepointer is at begin of item area. finally, the user might want to read. // using filepointer is essential here. // check the item api to allow this. return(tf); } catch (Exception) { tf.Dispose(); throw; } }
public void IsAccessibleWith(ItemDescription accessorDescription, ItemDescriptionElements elements) { // without descriptions in the file we cannot check anything. No warning will be issued in such case, // the user is responsible to check that files have descriptions if desired. if (this.Description == null) return; if (this.Description.ItemDescription == null) return; var fileDescription = this.Description.ItemDescription; fileDescription.IsAccessibleWith(accessorDescription, elements); }
/// <summary> /// Checks it the access description can access a time series based on this ItemDescription. /// </summary> /// <remarks> /// policies:<br></br> /// If <paramref name="accessorDescription"/> has no fields, the check will always succeed.<br></br> /// /// </remarks> /// <param name="accessorDescription">ItemDescription that describes the type used to access the file.</param> /// <param name="elementsToConsider">The amount of details used for the test.</param> /// <exception cref="TypeMismatchException">If the accessor type is not suitable to access the file.</exception> public void IsAccessibleWith(ItemDescription accessorDescription, ItemDescriptionElements elementsToConsider) { if (elementsToConsider.HasFlag(ItemDescriptionElements.ItemName)) { if (this.ItemTypeName != accessorDescription.itemTypeName) { throw new TypeMismatchException("ItemNames do not match: '{0}' vs '{1}'".Formatted(this.ItemTypeName, accessorDescription.ItemTypeName), "ItemName Check"); } } if (elementsToConsider.HasFlag(ItemDescriptionElements.ItemSize)) { if (this.ItemSize != accessorDescription.ItemSize) { throw new TypeMismatchException("ItemSizes do not match: {0} vs {1}".Formatted(this.ItemSize, accessorDescription.ItemSize), "ItemSize Check"); } } if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldOffsets)) { if (accessorDescription == null) { throw new ArgumentNullException("accessorDescription"); } if (!this.fields.Any()) { throw new TypeMismatchException("No fields are available in {0} to check field offsets. Empty structs are not supported by this API.".Formatted(this.Source.ToString()), "No ItemFields"); } if (!accessorDescription.fields.Any()) { throw new TypeMismatchException("No fields are available in {0} to check field offsets. Empty structs are not supported by this API.".Formatted(accessorDescription.Source.ToString()), "No ItemFields Accessor"); } var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset) == null); if (f != null) { throw new TypeMismatchException("Field has no field with matching byte offset:'{0}'".Formatted(f), "FieldOffsets Check"); } } if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldNames)) { if (accessorDescription == null) { throw new ArgumentNullException("accessorDescription"); } // ItemDescriptionDetails.FieldNames includes ItemDescriptionDetails.FieldOffsets by the definition of ItemDescriptionDetails values! var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset).Name != ff.Name); if (f != null) { throw new TypeMismatchException("Fields have different names: '{0}' vs '{1}'".Formatted(f, accessorDescription.FindFieldByOffset(f.Offset).Name), "FieldNames Check"); } } if (elementsToConsider.HasFlag(ItemDescriptionElements.FieldTypes)) { if (accessorDescription == null) { throw new ArgumentNullException("accessorDescription"); } // ItemDescriptionDetails.FieldNames includes ItemDescriptionDetails.FieldOffsets by the definition of ItemDescriptionDetails values! var f = this.Fields.FirstOrDefault(ff => accessorDescription.FindFieldByOffset(ff.Offset).FieldType != ff.FieldType); if (f != null) { throw new TypeMismatchException("Fields have different types: '{0}' vs '{1}'".Formatted(f, accessorDescription.FindFieldByOffset(f.Offset).Name), "FieldTypes Check"); } } }
static TeaFile <T> Append(Stream stream, bool ownsStream, Stream headerReadStream, ItemDescriptionElements elementsToValidate = ItemDescriptionElements.All) { var tf = new TeaFile <T>(); try { TeaFileDescription description; tf.core = new TeaFileCore(stream, ownsStream); // A file opened for appending, cannot be read. Therefore we create a second file, read it and assign its description to the current TeaFile<> instance. using (var tfheader = OpenRead(headerReadStream, false, elementsToValidate)) // we pass headerStream ownership to tfheader, so it will be closed after header reaeding. { description = tfheader.Description; if (!tfheader.core.CanAppend) { throw new IOException("Cannot append to file because it has preallocated space between the end of the item area and the end of the file."); } tf.core.Assign(tfheader.ItemAreaStart, tfheader.core.ItemAreaEndMarker); } // if the stream is a filestream that was opened in FileMode.Append, this call is redundant. // this line is here for the allowed case were the stream and headerstream point to the same stream. tf.SetFilePointerToEnd(); tf.core.Description = description; tf.buffer = new SafeBuffer <T>(stream); return(tf); } catch (Exception) { tf.Dispose(); throw; } }