问:
Controller function call from JS- JSON parse error - only in firefox
I have a button, which on click should insert the users into table.

Basically im stuck in calling the controller function from my javascript.

HTML button.

```<code><div class="continue_btton">
    <input type="submit" name="submit" id="SaveSettings" value="<?php echo $this->translate('Update'); ?>" class="update bdr_rds2" onclick="if($('input[name=target_criteria]:checked').val() == 'optedin_users')
                                                                                {
                                                                                return someFun()
                                                                                } else
                                                                                {
                                                                                return validateForm()
                                                                                }
    ">
</div>
</code>```

UPDATED:

Javascript

```<code> function someFun(){
    var urlInsert = '@Url.Action("myFunAction")';
        $.get(urlInsert, function () {
    });

}
</code>```

Also tried below, but the controller func not calling

```<code>function myFunAction(){
    var formData = $("#Preference").serialize();
    $.ajax({
        type: 'POST',
        url: '/advertiser/campaign/myFun',
        data: formData,
        dataType: 'html',
        success: function (data) {
            $('span.targetCount').text($.trim(data));
        },
        error: function (jqXHR, textStatus, errorThrown) {
            var error = $.parseJSON(jqXHR.responseText);
            var content = error.content;
            console.log(content.message);
            if (content.display_exceptions)
                console.log(content.exception.xdebug_message);
        },

    });
}
</code>```

Controller.php  - Doesnt seem to be called

```<code>public function myFunAction(){
    echo '+++myFUN---';exit;

}
</code>```

Error:

JSON.parse: unexpected character at line 1 column 1 of the JSON data

Tried dataType as html, json and text. Still same error.

答:
My guess is either your post data or your response object is not considered valid json and that is why Firefox throws an error (maybe Chrome is more forgiving). What you could check is whether the request is send correctly and whether the response from the server actually arrives and whether it is valid json. You should consider returning valid json from your myFunAction method in your controller (instead of just printing a string like you do right now):

```<code>public function myFunAction(){
    $data = '+++myFUN---';

    return new JsonModel([
        'data' => $data
    ]);
}
</code>```

Check more on how to properly return Json in Zend for example on this blog post here: https://akrabat.com/returning-json-from-a-zf2-controller-action/

Valid json response should have a content-type header set to application/json and have a valid json string in the response body. Zend JsonModel will help you with this.

When you post data you should also set the content-type of the request to application-json, like that the server understands that you are sending a json object with data.

I never use JQuery but I think it is done like this if I am not mistaken:

```<code>$.ajax({
  type: 'POST',
  url: '/advertiser/campaign/myFun',
  data: formData,
  contentType: "application/json",
});
</code>```

Body:
I have a button, which on click should insert the users into table.

Basically im stuck in calling the controller function from my javascript.

HTML button.

    <input type="submit" name="submit" id="SaveSettings" value="<?php echo $this->translate('Update'); ?>" class="update bdr_rds2" onclick="if($('input[name=target_criteria]:checked').val() == 'optedin_users')
                                                                                {
                                                                                return someFun()
                                                                                } else
                                                                                {
                                                                                return validateForm()
                                                                                }
    ">

UPDATED:

Javascript

 function someFun(){
    var urlInsert = '@Url.Action("myFunAction")';
        $.get(urlInsert, function () {
    });

}

Also tried below, but the controller func not calling

function myFunAction(){
    var formData = $("#Preference").serialize();
    $.ajax({
        type: 'POST',
        url: '/advertiser/campaign/myFun',
        data: formData,
        dataType: 'html',
        success: function (data) {
            $('span.targetCount').text($.trim(data));
        },
        error: function (jqXHR, textStatus, errorThrown) {
            var error = $.parseJSON(jqXHR.responseText);
            var content = error.content;
            console.log(content.message);
            if (content.display_exceptions)
                console.log(content.exception.xdebug_message);
        },

    });
}

Controller.php  - Doesnt seem to be called

public function myFunAction(){
    echo '+++myFUN---';exit;

}

Error:

JSON.parse: unexpected character at line 1 column 1 of the JSON data

Tried dataType as html, json and text. Still same error.

Body:
My guess is either your post data or your response object is not considered valid json and that is why Firefox throws an error (maybe Chrome is more forgiving). What you could check is whether the request is send correctly and whether the response from the server actually arrives and whether it is valid json. You should consider returning valid json from your myFunAction method in your controller (instead of just printing a string like you do right now):

public function myFunAction(){
    $data = '+++myFUN---';

    return new JsonModel([
        'data' => $data
    ]);
}

Check more on how to properly return Json in Zend for example on this blog post here: https://akrabat.com/returning-json-from-a-zf2-controller-action/

Valid json response should have a content-type header set to application/json and have a valid json string in the response body. Zend JsonModel will help you with this.

When you post data you should also set the content-type of the request to application-json, like that the server understands that you are sending a json object with data.

I never use JQuery but I think it is done like this if I am not mistaken:

$.ajax({
  type: 'POST',
  url: '/advertiser/campaign/myFun',
  data: formData,
  contentType: "application/json",
});


来源: stackexchange

问:
Python : Flatten xml, extract only the direct child without nested child
I am looking to flatten the xml to csv, and for each nested child entries, i want to replicate the value of direct child entry which both has same tag names. Here is the sample xml. For each value "entry" inside the "claim" tag, i want to print the values of all  for the direct child of "Insurer". I did try with findall but its retrieving the values of "entry" under "claim" as well.

Note: I'm Using ElementTree to parse

```<code><Parent>
       <Branch>
             <Insurer>
                  <claim>
                     <entry>1</entry>
                     <entry>2</entry>
                  </claim>
                  <entry>outer</entry>
                  <entry>outer1</entry>
                  <entry>outer2</entry>
              </Insurer>
        </Branch>
</Parent>
</code>```

```<code>Entry= child.findall('.//{http://trying.nz}entry')
</code>```

EXPECTED RESULT:

```<code>entry_from_claim,entry_from_Insurer
1,outer
1,outer1
1,outer2
2,outer
2,outer1
2,outer2
</code>```

答:
You failed to mention the xml parsing library you're using, but here's an example of working code based on ElementTree.

It does make assumptions about the structure of the XML data by using the find function that only goes one level deep.

```<code>#!/usr/bin/env python3

import xml.etree.ElementTree as ET

from csv import writer as csvwriter
from itertools import product

tree = ET.parse("input.xml")

claims = [
    entry.text
    for entry in tree.find("Branch")
    .find("Insurer")
    .find("claim")
    .findall("entry")
]
insurers = [
    entry.text
    for entry in tree.find("Branch").find("Insurer").findall("entry")
]

with open("output.csv", "w") as csvfile:
    outputwriter = csvwriter(csvfile)
    outputwriter.writerow(("entry_from_claim", "entry_from_Insurer"))
    outputwriter.writerows(product(claims, insurers))
</code>```

Hope this helps!

ContentLicense: CC BY-SA 4.0

Body:
I am looking to flatten the xml to csv, and for each nested child entries, i want to replicate the value of direct child entry which both has same tag names. Here is the sample xml. For each value "entry" inside the "claim" tag, i want to print the values of all  for the direct child of "Insurer". I did try with findall but its retrieving the values of "entry" under "claim" as well.

Note: I'm Using ElementTree to parse

<Parent>
       <Branch>
             <Insurer>
                  <claim>
                     <entry>1</entry>
                     <entry>2</entry>
                  </claim>
                  <entry>outer</entry>
                  <entry>outer1</entry>
                  <entry>outer2</entry>
              </Insurer>
        </Branch>
</Parent>

Entry= child.findall('.//{http://trying.nz}entry')

EXPECTED RESULT:

entry_from_claim,entry_from_Insurer
1,outer
1,outer1
1,outer2
2,outer
2,outer1
2,outer2

Body:
You failed to mention the xml parsing library you're using, but here's an example of working code based on ElementTree.

It does make assumptions about the structure of the XML data by using the find function that only goes one level deep.

#!/usr/bin/env python3

import xml.etree.ElementTree as ET

from csv import writer as csvwriter
from itertools import product

tree = ET.parse("input.xml")

claims = [
    entry.text
    for entry in tree.find("Branch")
    .find("Insurer")
    .find("claim")
    .findall("entry")
]
insurers = [
    entry.text
    for entry in tree.find("Branch").find("Insurer").findall("entry")
]

with open("output.csv", "w") as csvfile:
    outputwriter = csvwriter(csvfile)
    outputwriter.writerow(("entry_from_claim", "entry_from_Insurer"))
    outputwriter.writerows(product(claims, insurers))

Hope this helps!


问:
Buffered files (for faster disk access)
I am working with large files and writing directly to disk is slow. Because the file is large I cannot load it in a TMemoryStream.

TFileStream is not buffered so I want to know if there is a custom library that can offer buffered streams or should I rely only on the buffering offered by OS. Is the OS buffering reliable? I mean if the cache is full an old file (mine) might be flushed from cache in order to make room for a new file.

My file is in the GB range. It contains millions of records. Unfortunately, the records are not of fix size. So, I have to do millions of readings (between 4 and 500 bytes). The reading (and the writing) is sequential. I don't jump up and down into the file (which I think is ideal for buffering).

In the end, I have to write such file back to disk (again millions of small writes).

David provided the his personal library that provides buffered disk access.

```<code>   Speed tests:
     Input file: 317MB.SFF
     Delphi stream: 9.84sec
     David's stream: 2.05sec
     ______________________________________

   More tests:
     Input file: input2_700MB.txt
     Lines: 19 millions
     Compiler optimization: ON
     I/O check: On
     FastMM: release mode
     **HDD**

     Reading: **linear** (ReadLine) (PS: multiply time with 10)
      We see clear performance drop at 8KB. Recommended 16 or 32KB
        Time: 618 ms  Cache size: 64KB.
        Time: 622 ms  Cache size: 128KB.
        Time: 622 ms  Cache size: 24KB.
        Time: 622 ms  Cache size: 32KB.
        Time: 622 ms  Cache size: 64KB.
        Time: 624 ms  Cache size: 256KB.
        Time: 625 ms  Cache size: 18KB.
        Time: 626 ms  Cache size: 26KB.
        Time: 626 ms  Cache size: 1024KB.
        Time: 626 ms  Cache size: 16KB.
        Time: 628 ms  Cache size: 42KB.
        Time: 644 ms  Cache size: 8KB.      <--- no difference until 8K
        Time: 664 ms  Cache size: 4KB.
        Time: 705 ms  Cache size: 2KB.
        Time: 791 ms  Cache size: 1KB.
        Time: 795 ms  Cache size: 1KB.

      **SSD**
      We see a small improvement as we go towards higher buffers. Recommended 16 or 32KB
        Time: 610 ms  Cache size: 128KB.
        Time: 611 ms  Cache size: 256KB.
        Time: 614 ms  Cache size: 32KB.
        Time: 623 ms  Cache size: 16KB.
        Time: 625 ms  Cache size: 66KB.
        Time: 639 ms  Cache size: 8KB.       <--- definitively not good with 8K
        Time: 660 ms  Cache size: 4KB.
     ______

     Reading: **Random** (ReadInteger) (100000 reads)
     SSD
       Time: 064 ms. Cache size: 1KB.   Count: 100000.  RAM: 13.27 MB         <-- probably the best buffer size for ReadInteger is 4bytes!
       Time: 067 ms. Cache size: 2KB.   Count: 100000.  RAM: 13.27 MB
       Time: 080 ms. Cache size: 4KB.   Count: 100000.  RAM: 13.27 MB
       Time: 098 ms. Cache size: 8KB.   Count: 100000.  RAM: 13.27 MB
       Time: 140 ms. Cache size: 16KB.  Count: 100000.  RAM: 13.27 MB
       Time: 213 ms. Cache size: 32KB.  Count: 100000.  RAM: 13.27 MB
       Time: 360 ms. Cache size: 64KB.  Count: 100000.  RAM: 13.27 MB
       Conclusion: don't use it for "random" reading
</code>```

Update 2020:

When reading sequentially, the new System.Classes.TBufferedFileStream seems to be 70% faster than the library presented above.

答:
Windows file caching is very effective, especially if you are using Vista or later.  TFileStream is a loose wrapper around the Windows ReadFile() and WriteFile() API functions and for many use cases the only thing faster is a memory mapped file.

However, there is one common scenario where TFileStream becomes a performance bottleneck. That is if you read or write small amounts of data with each call to the stream read or write functions.  For example if you read an array of integers one item at a time then you incur a significant overhead by reading 4 bytes at a time in the calls to ReadFile().

Again, memory mapped files are an excellent way to solve this bottleneck, but the other commonly used approach is to read a much larger buffer, many kilobytes say, and then resolve future reads of the stream from this in memory cache rather than further calls to ReadFile().  This approach only really works for sequential access.

From the use pattern described in your updated question, I think you may find the following classes would improve performance for you:

```<code>unit BufferedFileStream;

interface

uses
  SysUtils, Math, Classes, Windows;

type
  TBaseCachedFileStream = class(TStream)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  protected
    FHandle: THandle;
    FOwnsHandle: Boolean;
    FCache: PByte;
    FCacheSize: Integer;
    FPosition: Int64;//the current position in the file (relative to the beginning of the file)
    FCacheStart: Int64;//the postion in the file of the start of the cache (relative to the beginning of the file)
    FCacheEnd: Int64;//the postion in the file of the end of the cache (relative to the beginning of the file)
    FFileName: string;
    FLastError: DWORD;
    procedure HandleError(const Msg: string);
    procedure RaiseSystemError(const Msg: string; LastError: DWORD); overload;
    procedure RaiseSystemError(const Msg: string); overload;
    procedure RaiseSystemErrorFmt(const Msg: string; const Args: array of const);
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; virtual; abstract;
    function GetFileSize: Int64; virtual;
    procedure SetSize(NewSize: Longint); override;
    procedure SetSize(const NewSize: Int64); override;
    function FileRead(var Buffer; Count: Longword): Integer;
    function FileWrite(const Buffer; Count: Longword): Integer;
    function FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  public
    constructor Create(const FileName: string); overload;
    constructor Create(const FileName: string; CacheSize: Integer); overload;
    constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; virtual;
    destructor Destroy; override;
    property CacheSize: Integer read FCacheSize;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  end;
  TBaseCachedFileStreamClass = class of TBaseCachedFileStream;

  IDisableStreamReadCache = interface
    ['{0B6D0004-88D1-42D5-BC0F-447911C0FC21}']
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
  end;

  TReadOnlyCachedFileStream = class(TBaseCachedFileStream, IDisableStreamReadCache)
  (* This class works by filling the cache each time a call to Read is made and
     FPosition is outside the existing cache.  By filling the cache we mean
     reading from the file into the temporary cache.  Calls to Read when
     FPosition is in the existing cache are then dealt with by filling the
     buffer with bytes from the cache.
  *)
  private
    FUseAlignedCache: Boolean;
    FViewStart: Int64;
    FViewLength: Int64;
    FDisableStreamReadCacheRefCount: Integer;
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
    procedure FlushCache;
  protected
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; override;
    function GetFileSize: Int64; override;
  public
    constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; override;
    property UseAlignedCache: Boolean read FUseAlignedCache write FUseAlignedCache;
    function Read(var Buffer; Count: Longint): Longint; override;
    procedure SetViewWindow(const ViewStart, ViewLength: Int64);
  end;

  TWriteCachedFileStream = class(TBaseCachedFileStream, IDisableStreamReadCache)
  (* This class works by caching calls to Write.  By this we mean temporarily
     storing the bytes to be written in the cache.  As each call to Write is
     processed the cache grows.  The cache is written to file when:
       1.  A call to Write is made when the cache is full.
       2.  A call to Write is made and FPosition is outside the cache (this
           must be as a result of a call to Seek).
       3.  The class is destroyed.

     Note that data can be read from these streams but the reading is not
     cached and in fact a read operation will flush the cache before
     attempting to read the data.
  *)
  private
    FFileSize: Int64;
    FReadStream: TReadOnlyCachedFileStream;
    FReadStreamCacheSize: Integer;
    FReadStreamUseAlignedCache: Boolean;
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
    procedure CreateReadStream;
    procedure FlushCache;
  protected
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; override;
    function GetFileSize: Int64; override;
  public
    constructor Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean); overload;
    destructor Destroy; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
  end;

implementation

function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external kernel32;
function SetFilePointerEx(hFile: THandle; DistanceToMove: Int64; lpNewFilePointer: PInt64; dwMoveMethod: DWORD): BOOL; stdcall; external kernel32;

{ TBaseCachedFileStream }

constructor TBaseCachedFileStream.Create(const FileName: string);
begin
  Create(FileName, 0);
end;

constructor TBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer);
begin
  Create(FileName, CacheSize, 0);
end;

constructor TBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle);
const
  DefaultCacheSize = 16*1024;
  //16kb - this was chosen empirically - don't make it too large otherwise the progress report is 'jerky'
begin
  inherited Create;
  FFileName := FileName;
  FOwnsHandle := Handle=0;
  if FOwnsHandle then begin
    FHandle := CreateHandle(FILE_ATTRIBUTE_NORMAL);
  end else begin
    FHandle := Handle;
  end;
  FCacheSize := CacheSize;
  if FCacheSize<=0 then begin
    FCacheSize := DefaultCacheSize;
  end;
  GetMem(FCache, FCacheSize);
end;

destructor TBaseCachedFileStream.Destroy;
begin
  FreeMem(FCache);
  if FOwnsHandle and (FHandle<>0) then begin
    CloseHandle(FHandle);
  end;
  inherited;
end;

function TBaseCachedFileStream.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then begin
    Result := S_OK;
  end else begin
    Result := E_NOINTERFACE;
  end;
end;

function TBaseCachedFileStream._AddRef: Integer;
begin
  Result := -1;
end;

function TBaseCachedFileStream._Release: Integer;
begin
  Result := -1;
end;

procedure TBaseCachedFileStream.HandleError(const Msg: string);
begin
  if FLastError<>0 then begin
    RaiseSystemError(Msg, FLastError);
  end;
end;

procedure TBaseCachedFileStream.RaiseSystemError(const Msg: string; LastError: DWORD);
begin
  raise EStreamError.Create(Trim(Msg+'  ')+SysErrorMessage(LastError));
end;

procedure TBaseCachedFileStream.RaiseSystemError(const Msg: string);
begin
  RaiseSystemError(Msg, GetLastError);
end;

procedure TBaseCachedFileStream.RaiseSystemErrorFmt(const Msg: string; const Args: array of const);
var
  LastError: DWORD;
begin
  LastError := GetLastError; // must call GetLastError before Format
  RaiseSystemError(Format(Msg, Args), LastError);
end;

function TBaseCachedFileStream.GetFileSize: Int64;
begin
  if not GetFileSizeEx(FHandle, Result) then begin
    RaiseSystemErrorFmt('GetFileSizeEx failed for %s.', [FFileName]);
  end;
end;

procedure TBaseCachedFileStream.SetSize(NewSize: Longint);
begin
  SetSize(Int64(NewSize));
end;

procedure TBaseCachedFileStream.SetSize(const NewSize: Int64);
begin
  Seek(NewSize, soBeginning);
  if not Windows.SetEndOfFile(FHandle) then begin
    RaiseSystemErrorFmt('SetEndOfFile for %s.', [FFileName]);
  end;
end;

function TBaseCachedFileStream.FileRead(var Buffer; Count: Longword): Integer;
begin
  if Windows.ReadFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin
    FLastError := 0;
  end else begin
    FLastError := GetLastError;
    Result := -1;
  end;
end;

function TBaseCachedFileStream.FileWrite(const Buffer; Count: Longword): Integer;
begin
  if Windows.WriteFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin
    FLastError := 0;
  end else begin
    FLastError := GetLastError;
    Result := -1;
  end;
end;

function TBaseCachedFileStream.FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  if not SetFilePointerEx(FHandle, Offset, @Result, ord(Origin)) then begin
    RaiseSystemErrorFmt('SetFilePointerEx failed for %s.', [FFileName]);
  end;
end;

function TBaseCachedFileStream.Read(var Buffer; Count: Integer): Longint;
begin
  raise EAssertionFailed.Create('Cannot read from this stream');
end;

function TBaseCachedFileStream.Write(const Buffer; Count: Integer): Longint;
begin
  raise EAssertionFailed.Create('Cannot write to this stream');
end;

function TBaseCachedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
//Set FPosition to the value specified - if this has implications for the
//cache then overriden Write and Read methods must deal with those.
begin
  case Origin of
  soBeginning:
    FPosition := Offset;
  soEnd:
    FPosition := GetFileSize+Offset;
  soCurrent:
    inc(FPosition, Offset);
  end;
  Result := FPosition;
end;

{ TReadOnlyCachedFileStream }

constructor TReadOnlyCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle);
begin
  inherited;
  SetViewWindow(0, inherited GetFileSize);
end;

function TReadOnlyCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle;
begin
  Result := Windows.CreateFile(
    PChar(FFileName),
    GENERIC_READ,
    FILE_SHARE_READ,
    nil,
    OPEN_EXISTING,
    FlagsAndAttributes,
    0
  );
  if Result=INVALID_HANDLE_VALUE then begin
    RaiseSystemErrorFmt('Cannot open %s.', [FFileName]);
  end;
end;

procedure TReadOnlyCachedFileStream.DisableStreamReadCache;
begin
  inc(FDisableStreamReadCacheRefCount);
end;

procedure TReadOnlyCachedFileStream.EnableStreamReadCache;
begin
  dec(FDisableStreamReadCacheRefCount);
end;

procedure TReadOnlyCachedFileStream.FlushCache;
begin
  FCacheStart := 0;
  FCacheEnd := 0;
end;

function TReadOnlyCachedFileStream.GetFileSize: Int64;
begin
  Result := FViewLength;
end;

procedure TReadOnlyCachedFileStream.SetViewWindow(const ViewStart, ViewLength: Int64);
begin
  if ViewStart<0 then begin
    raise EAssertionFailed.Create('Invalid view window');
  end;
  if (ViewStart+ViewLength)>inherited GetFileSize then begin
    raise EAssertionFailed.Create('Invalid view window');
  end;
  FViewStart := ViewStart;
  FViewLength := ViewLength;
  FPosition := 0;
  FCacheStart := 0;
  FCacheEnd := 0;
end;

function TReadOnlyCachedFileStream.Read(var Buffer; Count: Longint): Longint;
var
  NumOfBytesToCopy, NumOfBytesLeft, NumOfBytesRead: Longint;
  CachePtr, BufferPtr: PByte;
begin
  if FDisableStreamReadCacheRefCount>0 then begin
    FileSeek(FPosition+FViewStart, soBeginning);
    Result := FileRead(Buffer, Count);
    if Result=-1 then begin
      Result := 0;//contract is to return number of bytes that were read
    end;
    inc(FPosition, Result);
  end else begin
    Result := 0;
    NumOfBytesLeft := Count;
    BufferPtr := @Buffer;
    while NumOfBytesLeft>0 do begin
      if (FPosition<FCacheStart) or (FPosition>=FCacheEnd) then begin
        //the current position is not available in the cache so we need to re-fill the cache
        FCacheStart := FPosition;
        if UseAlignedCache then begin
          FCacheStart := FCacheStart - (FCacheStart mod CacheSize);
        end;
        FileSeek(FCacheStart+FViewStart, soBeginning);
        NumOfBytesRead := FileRead(FCache^, CacheSize);
        if NumOfBytesRead=-1 then begin
          exit;
        end;
        Assert(NumOfBytesRead>=0);
        FCacheEnd := FCacheStart+NumOfBytesRead;
        if NumOfBytesRead=0 then begin
          FLastError := ERROR_HANDLE_EOF;//must be at the end of the file
          break;
        end;
      end;

      //read from cache to Buffer
      NumOfBytesToCopy := Min(FCacheEnd-FPosition, NumOfBytesLeft);
      CachePtr := FCache;
      inc(CachePtr, FPosition-FCacheStart);
      Move(CachePtr^, BufferPtr^, NumOfBytesToCopy);
      inc(Result, NumOfBytesToCopy);
      inc(FPosition, NumOfBytesToCopy);
      inc(BufferPtr, NumOfBytesToCopy);
      dec(NumOfBytesLeft, NumOfBytesToCopy);
    end;
  end;
end;

{ TWriteCachedFileStream }

constructor TWriteCachedFileStream.Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean);
begin
  inherited Create(FileName, CacheSize);
  FReadStreamCacheSize := ReadStreamCacheSize;
  FReadStreamUseAlignedCache := ReadStreamUseAlignedCache;
end;

destructor TWriteCachedFileStream.Destroy;
begin
  FlushCache;//make sure that the final calls to Write get recorded in the file
  FreeAndNil(FReadStream);
  inherited;
end;

function TWriteCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle;
begin
  Result := Windows.CreateFile(
    PChar(FFileName),
    GENERIC_READ or GENERIC_WRITE,
    0,
    nil,
    CREATE_ALWAYS,
    FlagsAndAttributes,
    0
  );
  if Result=INVALID_HANDLE_VALUE then begin
    RaiseSystemErrorFmt('Cannot create %s.', [FFileName]);
  end;
end;

procedure TWriteCachedFileStream.DisableStreamReadCache;
begin
  CreateReadStream;
  FReadStream.DisableStreamReadCache;
end;

procedure TWriteCachedFileStream.EnableStreamReadCache;
begin
  Assert(Assigned(FReadStream));
  FReadStream.EnableStreamReadCache;
end;

function TWriteCachedFileStream.GetFileSize: Int64;
begin
  Result := FFileSize;
end;

procedure TWriteCachedFileStream.CreateReadStream;
begin
  if not Assigned(FReadStream) then begin
    FReadStream := TReadOnlyCachedFileStream.Create(FFileName, FReadStreamCacheSize, FHandle);
    FReadStream.UseAlignedCache := FReadStreamUseAlignedCache;
  end;
end;

procedure TWriteCachedFileStream.FlushCache;
var
  NumOfBytesToWrite: Longint;
begin
  if Assigned(FCache) then begin
    NumOfBytesToWrite := FCacheEnd-FCacheStart;
    if NumOfBytesToWrite>0 then begin
      FileSeek(FCacheStart, soBeginning);
      if FileWrite(FCache^, NumOfBytesToWrite)<>NumOfBytesToWrite then begin
        RaiseSystemErrorFmt('FileWrite failed for %s.', [FFileName]);
      end;
      if Assigned(FReadStream) then begin
        FReadStream.FlushCache;
      end;
    end;
    FCacheStart := FPosition;
    FCacheEnd := FPosition;
  end;
end;

function TWriteCachedFileStream.Read(var Buffer; Count: Integer): Longint;
begin
  FlushCache;
  CreateReadStream;
  Assert(FReadStream.FViewStart=0);
  if FReadStream.FViewLength<>FFileSize then begin
    FReadStream.SetViewWindow(0, FFileSize);
  end;
  FReadStream.Position := FPosition;
  Result := FReadStream.Read(Buffer, Count);
  inc(FPosition, Result);
end;

function TWriteCachedFileStream.Write(const Buffer; Count: Longint): Longint;
var
  NumOfBytesToCopy, NumOfBytesLeft: Longint;
  CachePtr, BufferPtr: PByte;
begin
  Result := 0;
  NumOfBytesLeft := Count;
  BufferPtr := @Buffer;
  while NumOfBytesLeft>0 do begin
    if ((FPosition<FCacheStart) or (FPosition>FCacheEnd))//the current position is outside the cache
    or (FPosition-FCacheStart=FCacheSize)//the cache is full
    then begin
      FlushCache;
      Assert(FCacheStart=FPosition);
    end;

    //write from Buffer to the cache
    NumOfBytesToCopy := Min(FCacheSize-(FPosition-FCacheStart), NumOfBytesLeft);
    CachePtr := FCache;
    inc(CachePtr, FPosition-FCacheStart);
    Move(BufferPtr^, CachePtr^, NumOfBytesToCopy);
    inc(Result, NumOfBytesToCopy);
    inc(FPosition, NumOfBytesToCopy);
    FCacheEnd := Max(FCacheEnd, FPosition);
    inc(BufferPtr, NumOfBytesToCopy);
    dec(NumOfBytesLeft, NumOfBytesToCopy);
  end;
  FFileSize := Max(FFileSize, FPosition);
end;

end.
</code>```

Title: Buffered files (for faster disk access)

Body:
I am working with large files and writing directly to disk is slow. Because the file is large I cannot load it in a TMemoryStream.

TFileStream is not buffered so I want to know if there is a custom library that can offer buffered streams or should I rely only on the buffering offered by OS. Is the OS buffering reliable? I mean if the cache is full an old file (mine) might be flushed from cache in order to make room for a new file.

My file is in the GB range. It contains millions of records. Unfortunately, the records are not of fix size. So, I have to do millions of readings (between 4 and 500 bytes). The reading (and the writing) is sequential. I don't jump up and down into the file (which I think is ideal for buffering).

In the end, I have to write such file back to disk (again millions of small writes).

David provided the his personal library that provides buffered disk access.

   Speed tests:
     Input file: 317MB.SFF
     Delphi stream: 9.84sec
     David's stream: 2.05sec
     ______________________________________

   More tests:
     Input file: input2_700MB.txt
     Lines: 19 millions
     Compiler optimization: ON
     I/O check: On
     FastMM: release mode
     **HDD**

     Reading: **linear** (ReadLine) (PS: multiply time with 10)
      We see clear performance drop at 8KB. Recommended 16 or 32KB
        Time: 618 ms  Cache size: 64KB.
        Time: 622 ms  Cache size: 128KB.
        Time: 622 ms  Cache size: 24KB.
        Time: 622 ms  Cache size: 32KB.
        Time: 622 ms  Cache size: 64KB.
        Time: 624 ms  Cache size: 256KB.
        Time: 625 ms  Cache size: 18KB.
        Time: 626 ms  Cache size: 26KB.
        Time: 626 ms  Cache size: 1024KB.
        Time: 626 ms  Cache size: 16KB.
        Time: 628 ms  Cache size: 42KB.
        Time: 644 ms  Cache size: 8KB.      <--- no difference until 8K
        Time: 664 ms  Cache size: 4KB.
        Time: 705 ms  Cache size: 2KB.
        Time: 791 ms  Cache size: 1KB.
        Time: 795 ms  Cache size: 1KB.

      **SSD**
      We see a small improvement as we go towards higher buffers. Recommended 16 or 32KB
        Time: 610 ms  Cache size: 128KB.
        Time: 611 ms  Cache size: 256KB.
        Time: 614 ms  Cache size: 32KB.
        Time: 623 ms  Cache size: 16KB.
        Time: 625 ms  Cache size: 66KB.
        Time: 639 ms  Cache size: 8KB.       <--- definitively not good with 8K
        Time: 660 ms  Cache size: 4KB.
     ______

     Reading: **Random** (ReadInteger) (100000 reads)
     SSD
       Time: 064 ms. Cache size: 1KB.   Count: 100000.  RAM: 13.27 MB         <-- probably the best buffer size for ReadInteger is 4bytes!
       Time: 067 ms. Cache size: 2KB.   Count: 100000.  RAM: 13.27 MB
       Time: 080 ms. Cache size: 4KB.   Count: 100000.  RAM: 13.27 MB
       Time: 098 ms. Cache size: 8KB.   Count: 100000.  RAM: 13.27 MB
       Time: 140 ms. Cache size: 16KB.  Count: 100000.  RAM: 13.27 MB
       Time: 213 ms. Cache size: 32KB.  Count: 100000.  RAM: 13.27 MB
       Time: 360 ms. Cache size: 64KB.  Count: 100000.  RAM: 13.27 MB
       Conclusion: don't use it for "random" reading

Update 2020:

When reading sequentially, the new System.Classes.TBufferedFileStream seems to be 70% faster than the library presented above.

Body:
Windows file caching is very effective, especially if you are using Vista or later.  TFileStream is a loose wrapper around the Windows ReadFile() and WriteFile() API functions and for many use cases the only thing faster is a memory mapped file.

However, there is one common scenario where TFileStream becomes a performance bottleneck. That is if you read or write small amounts of data with each call to the stream read or write functions.  For example if you read an array of integers one item at a time then you incur a significant overhead by reading 4 bytes at a time in the calls to ReadFile().

Again, memory mapped files are an excellent way to solve this bottleneck, but the other commonly used approach is to read a much larger buffer, many kilobytes say, and then resolve future reads of the stream from this in memory cache rather than further calls to ReadFile().  This approach only really works for sequential access.

From the use pattern described in your updated question, I think you may find the following classes would improve performance for you:

unit BufferedFileStream;

interface

uses
  SysUtils, Math, Classes, Windows;

type
  TBaseCachedFileStream = class(TStream)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  protected
    FHandle: THandle;
    FOwnsHandle: Boolean;
    FCache: PByte;
    FCacheSize: Integer;
    FPosition: Int64;//the current position in the file (relative to the beginning of the file)
    FCacheStart: Int64;//the postion in the file of the start of the cache (relative to the beginning of the file)
    FCacheEnd: Int64;//the postion in the file of the end of the cache (relative to the beginning of the file)
    FFileName: string;
    FLastError: DWORD;
    procedure HandleError(const Msg: string);
    procedure RaiseSystemError(const Msg: string; LastError: DWORD); overload;
    procedure RaiseSystemError(const Msg: string); overload;
    procedure RaiseSystemErrorFmt(const Msg: string; const Args: array of const);
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; virtual; abstract;
    function GetFileSize: Int64; virtual;
    procedure SetSize(NewSize: Longint); override;
    procedure SetSize(const NewSize: Int64); override;
    function FileRead(var Buffer; Count: Longword): Integer;
    function FileWrite(const Buffer; Count: Longword): Integer;
    function FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  public
    constructor Create(const FileName: string); overload;
    constructor Create(const FileName: string; CacheSize: Integer); overload;
    constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; virtual;
    destructor Destroy; override;
    property CacheSize: Integer read FCacheSize;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  end;
  TBaseCachedFileStreamClass = class of TBaseCachedFileStream;

  IDisableStreamReadCache = interface
    ['{0B6D0004-88D1-42D5-BC0F-447911C0FC21}']
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
  end;

  TReadOnlyCachedFileStream = class(TBaseCachedFileStream, IDisableStreamReadCache)
  (* This class works by filling the cache each time a call to Read is made and
     FPosition is outside the existing cache.  By filling the cache we mean
     reading from the file into the temporary cache.  Calls to Read when
     FPosition is in the existing cache are then dealt with by filling the
     buffer with bytes from the cache.
  *)
  private
    FUseAlignedCache: Boolean;
    FViewStart: Int64;
    FViewLength: Int64;
    FDisableStreamReadCacheRefCount: Integer;
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
    procedure FlushCache;
  protected
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; override;
    function GetFileSize: Int64; override;
  public
    constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; override;
    property UseAlignedCache: Boolean read FUseAlignedCache write FUseAlignedCache;
    function Read(var Buffer; Count: Longint): Longint; override;
    procedure SetViewWindow(const ViewStart, ViewLength: Int64);
  end;

  TWriteCachedFileStream = class(TBaseCachedFileStream, IDisableStreamReadCache)
  (* This class works by caching calls to Write.  By this we mean temporarily
     storing the bytes to be written in the cache.  As each call to Write is
     processed the cache grows.  The cache is written to file when:
       1.  A call to Write is made when the cache is full.
       2.  A call to Write is made and FPosition is outside the cache (this
           must be as a result of a call to Seek).
       3.  The class is destroyed.

     Note that data can be read from these streams but the reading is not
     cached and in fact a read operation will flush the cache before
     attempting to read the data.
  *)
  private
    FFileSize: Int64;
    FReadStream: TReadOnlyCachedFileStream;
    FReadStreamCacheSize: Integer;
    FReadStreamUseAlignedCache: Boolean;
    procedure DisableStreamReadCache;
    procedure EnableStreamReadCache;
    procedure CreateReadStream;
    procedure FlushCache;
  protected
    function CreateHandle(FlagsAndAttributes: DWORD): THandle; override;
    function GetFileSize: Int64; override;
  public
    constructor Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean); overload;
    destructor Destroy; override;
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
  end;

implementation

function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external kernel32;
function SetFilePointerEx(hFile: THandle; DistanceToMove: Int64; lpNewFilePointer: PInt64; dwMoveMethod: DWORD): BOOL; stdcall; external kernel32;

{ TBaseCachedFileStream }

constructor TBaseCachedFileStream.Create(const FileName: string);
begin
  Create(FileName, 0);
end;

constructor TBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer);
begin
  Create(FileName, CacheSize, 0);
end;

constructor TBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle);
const
  DefaultCacheSize = 16*1024;
  //16kb - this was chosen empirically - don't make it too large otherwise the progress report is 'jerky'
begin
  inherited Create;
  FFileName := FileName;
  FOwnsHandle := Handle=0;
  if FOwnsHandle then begin
    FHandle := CreateHandle(FILE_ATTRIBUTE_NORMAL);
  end else begin
    FHandle := Handle;
  end;
  FCacheSize := CacheSize;
  if FCacheSize<=0 then begin
    FCacheSize := DefaultCacheSize;
  end;
  GetMem(FCache, FCacheSize);
end;

destructor TBaseCachedFileStream.Destroy;
begin
  FreeMem(FCache);
  if FOwnsHandle and (FHandle<>0) then begin
    CloseHandle(FHandle);
  end;
  inherited;
end;

function TBaseCachedFileStream.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then begin
    Result := S_OK;
  end else begin
    Result := E_NOINTERFACE;
  end;
end;

function TBaseCachedFileStream._AddRef: Integer;
begin
  Result := -1;
end;

function TBaseCachedFileStream._Release: Integer;
begin
  Result := -1;
end;

procedure TBaseCachedFileStream.HandleError(const Msg: string);
begin
  if FLastError<>0 then begin
    RaiseSystemError(Msg, FLastError);
  end;
end;

procedure TBaseCachedFileStream.RaiseSystemError(const Msg: string; LastError: DWORD);
begin
  raise EStreamError.Create(Trim(Msg+'  ')+SysErrorMessage(LastError));
end;

procedure TBaseCachedFileStream.RaiseSystemError(const Msg: string);
begin
  RaiseSystemError(Msg, GetLastError);
end;

procedure TBaseCachedFileStream.RaiseSystemErrorFmt(const Msg: string; const Args: array of const);
var
  LastError: DWORD;
begin
  LastError := GetLastError; // must call GetLastError before Format
  RaiseSystemError(Format(Msg, Args), LastError);
end;

function TBaseCachedFileStream.GetFileSize: Int64;
begin
  if not GetFileSizeEx(FHandle, Result) then begin
    RaiseSystemErrorFmt('GetFileSizeEx failed for %s.', [FFileName]);
  end;
end;

procedure TBaseCachedFileStream.SetSize(NewSize: Longint);
begin
  SetSize(Int64(NewSize));
end;

procedure TBaseCachedFileStream.SetSize(const NewSize: Int64);
begin
  Seek(NewSize, soBeginning);
  if not Windows.SetEndOfFile(FHandle) then begin
    RaiseSystemErrorFmt('SetEndOfFile for %s.', [FFileName]);
  end;
end;

function TBaseCachedFileStream.FileRead(var Buffer; Count: Longword): Integer;
begin
  if Windows.ReadFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin
    FLastError := 0;
  end else begin
    FLastError := GetLastError;
    Result := -1;
  end;
end;

function TBaseCachedFileStream.FileWrite(const Buffer; Count: Longword): Integer;
begin
  if Windows.WriteFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin
    FLastError := 0;
  end else begin
    FLastError := GetLastError;
    Result := -1;
  end;
end;

function TBaseCachedFileStream.FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  if not SetFilePointerEx(FHandle, Offset, @Result, ord(Origin)) then begin
    RaiseSystemErrorFmt('SetFilePointerEx failed for %s.', [FFileName]);
  end;
end;

function TBaseCachedFileStream.Read(var Buffer; Count: Integer): Longint;
begin
  raise EAssertionFailed.Create('Cannot read from this stream');
end;

function TBaseCachedFileStream.Write(const Buffer; Count: Integer): Longint;
begin
  raise EAssertionFailed.Create('Cannot write to this stream');
end;

function TBaseCachedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
//Set FPosition to the value specified - if this has implications for the
//cache then overriden Write and Read methods must deal with those.
begin
  case Origin of
  soBeginning:
    FPosition := Offset;
  soEnd:
    FPosition := GetFileSize+Offset;
  soCurrent:
    inc(FPosition, Offset);
  end;
  Result := FPosition;
end;

{ TReadOnlyCachedFileStream }

constructor TReadOnlyCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle);
begin
  inherited;
  SetViewWindow(0, inherited GetFileSize);
end;

function TReadOnlyCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle;
begin
  Result := Windows.CreateFile(
    PChar(FFileName),
    GENERIC_READ,
    FILE_SHARE_READ,
    nil,
    OPEN_EXISTING,
    FlagsAndAttributes,
    0
  );
  if Result=INVALID_HANDLE_VALUE then begin
    RaiseSystemErrorFmt('Cannot open %s.', [FFileName]);
  end;
end;

procedure TReadOnlyCachedFileStream.DisableStreamReadCache;
begin
  inc(FDisableStreamReadCacheRefCount);
end;

procedure TReadOnlyCachedFileStream.EnableStreamReadCache;
begin
  dec(FDisableStreamReadCacheRefCount);
end;

procedure TReadOnlyCachedFileStream.FlushCache;
begin
  FCacheStart := 0;
  FCacheEnd := 0;
end;

function TReadOnlyCachedFileStream.GetFileSize: Int64;
begin
  Result := FViewLength;
end;

procedure TReadOnlyCachedFileStream.SetViewWindow(const ViewStart, ViewLength: Int64);
begin
  if ViewStart<0 then begin
    raise EAssertionFailed.Create('Invalid view window');
  end;
  if (ViewStart+ViewLength)>inherited GetFileSize then begin
    raise EAssertionFailed.Create('Invalid view window');
  end;
  FViewStart := ViewStart;
  FViewLength := ViewLength;
  FPosition := 0;
  FCacheStart := 0;
  FCacheEnd := 0;
end;

function TReadOnlyCachedFileStream.Read(var Buffer; Count: Longint): Longint;
var
  NumOfBytesToCopy, NumOfBytesLeft, NumOfBytesRead: Longint;
  CachePtr, BufferPtr: PByte;
begin
  if FDisableStreamReadCacheRefCount>0 then begin
    FileSeek(FPosition+FViewStart, soBeginning);
    Result := FileRead(Buffer, Count);
    if Result=-1 then begin
      Result := 0;//contract is to return number of bytes that were read
    end;
    inc(FPosition, Result);
  end else begin
    Result := 0;
    NumOfBytesLeft := Count;
    BufferPtr := @Buffer;
    while NumOfBytesLeft>0 do begin
      if (FPosition<FCacheStart) or (FPosition>=FCacheEnd) then begin
        //the current position is not available in the cache so we need to re-fill the cache
        FCacheStart := FPosition;
        if UseAlignedCache then begin
          FCacheStart := FCacheStart - (FCacheStart mod CacheSize);
        end;
        FileSeek(FCacheStart+FViewStart, soBeginning);
        NumOfBytesRead := FileRead(FCache^, CacheSize);
        if NumOfBytesRead=-1 then begin
          exit;
        end;
        Assert(NumOfBytesRead>=0);
        FCacheEnd := FCacheStart+NumOfBytesRead;
        if NumOfBytesRead=0 then begin
          FLastError := ERROR_HANDLE_EOF;//must be at the end of the file
          break;
        end;
      end;

      //read from cache to Buffer
      NumOfBytesToCopy := Min(FCacheEnd-FPosition, NumOfBytesLeft);
      CachePtr := FCache;
      inc(CachePtr, FPosition-FCacheStart);
      Move(CachePtr^, BufferPtr^, NumOfBytesToCopy);
      inc(Result, NumOfBytesToCopy);
      inc(FPosition, NumOfBytesToCopy);
      inc(BufferPtr, NumOfBytesToCopy);
      dec(NumOfBytesLeft, NumOfBytesToCopy);
    end;
  end;
end;

{ TWriteCachedFileStream }

constructor TWriteCachedFileStream.Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean);
begin
  inherited Create(FileName, CacheSize);
  FReadStreamCacheSize := ReadStreamCacheSize;
  FReadStreamUseAlignedCache := ReadStreamUseAlignedCache;
end;

destructor TWriteCachedFileStream.Destroy;
begin
  FlushCache;//make sure that the final calls to Write get recorded in the file
  FreeAndNil(FReadStream);
  inherited;
end;

function TWriteCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle;
begin
  Result := Windows.CreateFile(
    PChar(FFileName),
    GENERIC_READ or GENERIC_WRITE,
    0,
    nil,
    CREATE_ALWAYS,
    FlagsAndAttributes,
    0
  );
  if Result=INVALID_HANDLE_VALUE then begin
    RaiseSystemErrorFmt('Cannot create %s.', [FFileName]);
  end;
end;

procedure TWriteCachedFileStream.DisableStreamReadCache;
begin
  CreateReadStream;
  FReadStream.DisableStreamReadCache;
end;

procedure TWriteCachedFileStream.EnableStreamReadCache;
begin
  Assert(Assigned(FReadStream));
  FReadStream.EnableStreamReadCache;
end;

function TWriteCachedFileStream.GetFileSize: Int64;
begin
  Result := FFileSize;
end;

procedure TWriteCachedFileStream.CreateReadStream;
begin
  if not Assigned(FReadStream) then begin
    FReadStream := TReadOnlyCachedFileStream.Create(FFileName, FReadStreamCacheSize, FHandle);
    FReadStream.UseAlignedCache := FReadStreamUseAlignedCache;
  end;
end;

procedure TWriteCachedFileStream.FlushCache;
var
  NumOfBytesToWrite: Longint;
begin
  if Assigned(FCache) then begin
    NumOfBytesToWrite := FCacheEnd-FCacheStart;
    if NumOfBytesToWrite>0 then begin
      FileSeek(FCacheStart, soBeginning);
      if FileWrite(FCache^, NumOfBytesToWrite)<>NumOfBytesToWrite then begin
        RaiseSystemErrorFmt('FileWrite failed for %s.', [FFileName]);
      end;
      if Assigned(FReadStream) then begin
        FReadStream.FlushCache;
      end;
    end;
    FCacheStart := FPosition;
    FCacheEnd := FPosition;
  end;
end;

function TWriteCachedFileStream.Read(var Buffer; Count: Integer): Longint;
begin
  FlushCache;
  CreateReadStream;
  Assert(FReadStream.FViewStart=0);
  if FReadStream.FViewLength<>FFileSize then begin
    FReadStream.SetViewWindow(0, FFileSize);
  end;
  FReadStream.Position := FPosition;
  Result := FReadStream.Read(Buffer, Count);
  inc(FPosition, Result);
end;

function TWriteCachedFileStream.Write(const Buffer; Count: Longint): Longint;
var
  NumOfBytesToCopy, NumOfBytesLeft: Longint;
  CachePtr, BufferPtr: PByte;
begin
  Result := 0;
  NumOfBytesLeft := Count;
  BufferPtr := @Buffer;
  while NumOfBytesLeft>0 do begin
    if ((FPosition<FCacheStart) or (FPosition>FCacheEnd))//the current position is outside the cache
    or (FPosition-FCacheStart=FCacheSize)//the cache is full
    then begin
      FlushCache;
      Assert(FCacheStart=FPosition);
    end;

    //write from Buffer to the cache
    NumOfBytesToCopy := Min(FCacheSize-(FPosition-FCacheStart), NumOfBytesLeft);
    CachePtr := FCache;
    inc(CachePtr, FPosition-FCacheStart);
    Move(BufferPtr^, CachePtr^, NumOfBytesToCopy);
    inc(Result, NumOfBytesToCopy);
    inc(FPosition, NumOfBytesToCopy);
    FCacheEnd := Max(FCacheEnd, FPosition);
    inc(BufferPtr, NumOfBytesToCopy);
    dec(NumOfBytesLeft, NumOfBytesToCopy);
  end;
  FFileSize := Max(FFileSize, FPosition);
end;

end.

ContentLicense: CC BY-SA 3.0


问:
How to close application using hardware back button
The hardware back button does not closes the application in Ionic 4 either with cordova or capacitor.

This feature was working in Ionic 3 but now in Ionic 4 it only navigates back.

Is there a way out to close the application using hardware back button.

答:
Here is the solution : in homepage.ts </p>

```<code>ionViewDidEnter(){
 this.subscription = this.platform.backButton.subscribe(()=>{
navigator['app'].exitApp(); }); }

ionViewWillLeave(){
this.subscription.unsubscribe(); }
</code>```

Body:
Here is the solution : in homepage.ts

ionViewDidEnter(){
 this.subscription = this.platform.backButton.subscribe(()=>{
navigator['app'].exitApp(); }); }

ionViewWillLeave(){
this.subscription.unsubscribe(); }


问:
Not getting all the necessary data when going through my loop in php
I'm trying to create a page where I list all the users that sold items on different months, but each user could have sold the items on different days of the month. This is what
I'm trying to get.

```<code>January
user 1
user 4
user 5

February
user 4
user 2
user 3
</code>```

I've managed to get it to list the months, but it only displays one user per month. For example

```<code>January
user 1

February
user 4
</code>```

Here is my code

```<code>$sql = "SELECT * FROM users INNER JOIN items ON users.id = items.user_id GROUP BY Year(items.sold_date), Month(items.sold_date)";
$result = mysqli_query($con, $sql);

$mnt = "";
while($row = mysqli_fetch_array($result))
{
    if($row['sold_date'] != $mnt)
    {
        echo date('F, Y', strtotime($row['order_date']));
        echo "<br/>";
    }

    echo $row['name'];
}
</code>```

My users table

```<code>id | name   | lastname
1  | user 1 | user 1 lastname
2  | user 2 | user 2 lastname
3  | user 3 | user 3 lastname
4  | user 4 | user 4 lastname
5  | user 5 | user 5 lastname
</code>```

my items table

```<code>id| name   |description         | user_id | sold_date
1 | item 1 | item 1 description | 3       | 2017-01-25
2 | item 2 | item 2 description | 1       | 2017-01-30
3 | item 3 | item 3 description | 5       | 2017-02-14
4 | item 4 | item 4 description | 2       | 2017-05-01
5 | item 5 | item 5 description | 1       | 2018-09-06
6 | item 6 | item 6 description | 4       | 2018-10-23
</code>```

I hope I've explained properly. If not please let me know.

答:
I would recommend using GROUP_CONCAT() if you want to print the ids in a single line with a delimiter.  The query would look something like this:

```<code>SELECT
    Year(items.sold_date) as 'Year Sold',
    Month(items.sold_date as 'Month Sold',
    GROUP_CONCAT(distinct users.id) as 'Unique User Ids'
FROM users
INNER JOIN items
ON users.id = items.user_id
GROUP BY
    Year(items.sold_date),
    Month(items.sold_date);
</code>```

If you are looking to get the desired results on several lines per year/month, you can just add the users.id column to your group by:

```<code>SELECT * FROM users
INNER JOIN items
ON users.id = items.user_id
GROUP BY
    Year(items.sold_date),
    Month(items.sold_date),
    users.id;
</code>```

Body:
I'm trying to create a page where I list all the users that sold items on different months, but each user could have sold the items on different days of the month. This is what
I'm trying to get.

January
user 1
user 4
user 5

February
user 4
user 2
user 3

I've managed to get it to list the months, but it only displays one user per month. For example

January
user 1

February
user 4

Here is my code

$sql = "SELECT * FROM users INNER JOIN items ON users.id = items.user_id GROUP BY Year(items.sold_date), Month(items.sold_date)";
$result = mysqli_query($con, $sql);

$mnt = "";
while($row = mysqli_fetch_array($result))
{
    if($row['sold_date'] != $mnt)
    {
        echo date('F, Y', strtotime($row['order_date']));
        echo "
";
    }

    echo $row['name'];
}

My users table

id | name   | lastname
1  | user 1 | user 1 lastname
2  | user 2 | user 2 lastname
3  | user 3 | user 3 lastname
4  | user 4 | user 4 lastname
5  | user 5 | user 5 lastname

my items table

id| name   |description         | user_id | sold_date
1 | item 1 | item 1 description | 3       | 2017-01-25
2 | item 2 | item 2 description | 1       | 2017-01-30
3 | item 3 | item 3 description | 5       | 2017-02-14
4 | item 4 | item 4 description | 2       | 2017-05-01
5 | item 5 | item 5 description | 1       | 2018-09-06
6 | item 6 | item 6 description | 4       | 2018-10-23

I hope I've explained properly. If not please let me know.

Body:
I would recommend using GROUP_CONCAT() if you want to print the ids in a single line with a delimiter.  The query would look something like this:

SELECT
    Year(items.sold_date) as 'Year Sold',
    Month(items.sold_date as 'Month Sold',
    GROUP_CONCAT(distinct users.id) as 'Unique User Ids'
FROM users
INNER JOIN items
ON users.id = items.user_id
GROUP BY
    Year(items.sold_date),
    Month(items.sold_date);

If you are looking to get the desired results on several lines per year/month, you can just add the users.id column to your group by:

SELECT * FROM users
INNER JOIN items
ON users.id = items.user_id
GROUP BY
    Year(items.sold_date),
    Month(items.sold_date),
    users.id;


问:
awk complains about non-terminated string in command from concatenated strings
So the background is that I'm using date command inside awk. This command has differing flags on Linux/GNU from OSX. I'm storing correct command with flags in $date variable to work around this. The following awk command (that relies on string concatenation) fails:

```<code>awk '{
    cmd = "'$date'" substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}'
</code>```

with error:

```<code>awk: non-terminated string date... at source line 2
 context is
         >>>  <<<
awk: giving up
 source line number 3
</code>```

When replacing awk with echo, the command outputs correctly:

```<code>{
    cmd = "date -r " substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}
</code>```

When the above script is put into awk directly, it also parses dates correctly (it takes first argument from each line of stdin as timestamp, strips microseconds and converts date to human-readable format).

$date variable is populated as follows:

```<code>date="date -d @"
date -d @1550000000 &>/dev/null
if [ $? -eq 1 ]; then
    date="date -r "
fi
</code>```

答:
You should always use -v name=value syntax to pass shell variables to awk.

So in your case:

```<code>dt="date -r"

awk -v dt="$dt" '{
   cmd = dt substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
   if ( (cmd | getline dd) > 0 ) {
       $1 = dd
   }
   close(cmd)
   print
}'
</code>```

More on: How do I use shell variables in awk scripts?

Also note helpful comment by Ed below that awk index starts at 1 instead of 0 in other languages such as C/C++.

Body:
So the background is that I'm using date command inside awk. This command has differing flags on Linux/GNU from OSX. I'm storing correct command with flags in $date variable to work around this. The following awk command (that relies on string concatenation) fails:

awk '{
    cmd = "'$date'" substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}'

with error:

awk: non-terminated string date... at source line 2
 context is
         >>>  <<<
awk: giving up
 source line number 3

When replacing awk with echo, the command outputs correctly:

{
    cmd = "date -r " substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
    if ( (cmd | getline dd) > 0 ) {
        $1 = dd
    }
    close(cmd)
    print
}

When the above script is put into awk directly, it also parses dates correctly (it takes first argument from each line of stdin as timestamp, strips microseconds and converts date to human-readable format).

$date variable is populated as follows:

date="date -d @"
date -d @1550000000 &>/dev/null
if [ $? -eq 1 ]; then
    date="date -r "
fi

Body:
You should always use -v name=value syntax to pass shell variables to awk.

So in your case:

dt="date -r"

awk -v dt="$dt" '{
   cmd = dt substr( $1, 1, length($1) - 3 ) " +\"%Y-%m-%d %H:%M\""
   if ( (cmd | getline dd) > 0 ) {
       $1 = dd
   }
   close(cmd)
   print
}'

More on: How do I use shell variables in awk scripts?

Also note helpful comment by Ed below that awk index starts at 1 instead of 0 in other languages such as C/C++.


问:
Is it enough to mention which browser you want to run the tests with in serenity.properties file?
Is it enough to mention which browser you want to run the tests with in serenity.properties file ?
Like...

Chrome Browser Testing
webdriver.driver=chrome
headless.mode = true

```<code>drivers.windows.webdriver.chrome.driver = src/test/resources/webdriver/windows/chromedriver.exe
drivers.mac.webdriver.chrome.driver = src/test/resources/webdriver/mac/chromedriver
drivers.linux.webdriver.chrome.driver = src/test/resources/webdriver/linux/chromedriver

Firefox Browser Testing
webdriver.driver=firefox
gecko.firefox.options = {"args": ["-headless"]}
drivers.mac.webdriver.gecko.driver = src/test/resources/webdriver/mac/geckodriver
drivers.linux.webdriver.firefox.driver = src/test/resources/webdriver/linux/geckodriver
</code>```

and invoke the test using command line like...
mvn clean verify -DuserId='xxx' -Dpasscode='xxx'

OR SHOULD I MENTION ALSO..

``mvn clean verify -Dwebdriver.driver=browser -DuserId='xxx' -Dpasscode='xxx'

Will Serenity infer it from properties file alone ?
Because when I don't give any browser in command prompt, and mention only firefox in properties file, it is looking for ChromeDriver and failing, whose path is properly given in properties file already.
Which option takes priority or which overrides which ?
I agree these are silly little questions !!

答:
The command line will override the property file.

So if you want to remove the webdriver.driver from the command line and move it into the properties that will work fine, it will grab from the properties file.
Then you can overwrite it later using the command line webdriver.driver.

Also I should note that almost all commands can be moved into the serenity properties file. Also you can setup multiple properties files for the different setups, devices, and tests you need to run.

I run over 15 different properties files for different settings on different devices. Then all I have to do is reference the property file in the command via: -Dproperties=properties/desktop.properties

Also one more note, my preference is to leave the webdriver.driver in the command line it makes it easier to run the same tests on the same device with different browser setups. I then create simple bash scripts that run my acceptance tests, smoke tests, regression tests, and does it on several different devices from desktop to mobile and then tests on the different browsers on the different nodes. But to each their own.

Body:
Is it enough to mention which browser you want to run the tests with in serenity.properties file ?
Like...

Chrome Browser Testing
webdriver.driver=chrome
headless.mode = true

drivers.windows.webdriver.chrome.driver = src/test/resources/webdriver/windows/chromedriver.exe
drivers.mac.webdriver.chrome.driver = src/test/resources/webdriver/mac/chromedriver
drivers.linux.webdriver.chrome.driver = src/test/resources/webdriver/linux/chromedriver

Firefox Browser Testing
webdriver.driver=firefox
gecko.firefox.options = {"args": ["-headless"]}
drivers.mac.webdriver.gecko.driver = src/test/resources/webdriver/mac/geckodriver
drivers.linux.webdriver.firefox.driver = src/test/resources/webdriver/linux/geckodriver

and invoke the test using command line like...
mvn clean verify -DuserId='xxx' -Dpasscode='xxx'

OR SHOULD I MENTION ALSO..

``mvn clean verify -Dwebdriver.driver=browser -DuserId='xxx' -Dpasscode='xxx'

Will Serenity infer it from properties file alone ?
Because when I don't give any browser in command prompt, and mention only firefox in properties file, it is looking for ChromeDriver and failing, whose path is properly given in properties file already.
Which option takes priority or which overrides which ?
I agree these are silly little questions !!


问:
Accessing nested JavaScript objects and arrays by string path
I have a data structure like this :

```<code>var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};
</code>```

And I would like to access the data using these variable :

```<code>var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";
</code>```

part1name should be filled with someObject.part1.name 's value, which is "Part 1". Same thing with part2quantity which filled with 60.

Is there anyway to achieve this with either pure javascript or JQuery?

答:
Extension of Mohamad Hamouday' Answer will fill in missing keys

```<code>function Object_Manager(obj, Path, value, Action, strict)
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            console.log(level,':',a, '|||',b)
            if (!strict){
              if (!(b in a)) a[b] = {}
            }

            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            }
            else
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

</code>```

Example

```<code>
obja = {
  "a": {
    "b":"nom"
  }
}

// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);

// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }

</code>```

Body:
I have a data structure like this :

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

And I would like to access the data using these variable :

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

part1name should be filled with someObject.part1.name 's value, which is "Part 1". Same thing with part2quantity which filled with 60.

Is there anyway to achieve this with either pure javascript or JQuery?

Body:
Extension of Mohamad Hamouday' Answer will fill in missing keys

function Object_Manager(obj, Path, value, Action, strict)
{
    try
    {
        if(Array.isArray(Path) == false)
        {
            Path = [Path];
        }

        let level = 0;
        var Return_Value;
        Path.reduce((a, b)=>{
            console.log(level,':',a, '|||',b)
            if (!strict){
              if (!(b in a)) a[b] = {}
            }

            level++;
            if (level === Path.length)
            {
                if(Action === 'Set')
                {
                    a[b] = value;
                    return value;
                }
                else if(Action === 'Get')
                {
                    Return_Value = a[b];
                }
                else if(Action === 'Unset')
                {
                    delete a[b];
                }
            }
            else
            {
                return a[b];
            }
        }, obj);
        return Return_Value;
    }

    catch(err)
    {
        console.error(err);
        return obj;
    }
}

Example

obja = {
  "a": {
    "b":"nom"
  }
}

// Set
path = "c.b" // Path does not exist
Object_Manager(obja,path.split('.'), 'test_new_val', 'Set', false);

// Expected Output: Object { a: Object { b: "nom" }, c: Object { b: "test_new_value" } }


问:
UI5: change the style of list items after clicking on a button
I want to dynamically change the style of a sap.m.CustomListItem of my list when I click on a button.

I used addStyleClass and it works only in the onInit method but not in the press` function, the style has been added but the view doesn't change.

Controller

pressbutton: function(oEvent) {
  var o = oEvent.getParameter("value");
  MessageToast.show(o.toString());
  var listitem = this.getView().byId("IDCustomerListItem");
  if (listitem.hasStyleClass("myListItemClass")) {
    this.getView().byId("IDCustomerListItem").removeStyleClass("myListItemClass");
    this.getView().byId("IDCustomerListItem").addStyleClass("myListItemClasso");
  } else {
    this.getView().byId("IDCustomerListItem").addStyleClass("myListItemClass");
  }
}
```

<h1>CSS</h1>

<pre class="lang-css prettyprint-override"><code>.myListItemClass {
  width: 50% !important;
  float: left;
}

.myListItemClasso {
  width: 100% !important;
}
</code>```

答:
If it works in the onInit but not inside your pressbutton event handler, I assume the following:

1) The handler is not assigned to the press event of your Button

2) Your list has many items and you are not correctly getting the IDs of the items.

It's confusing in your question what are the controls assigned to the IDs and it would be easier to check the root cause of that issue having the source code of your view as well.

Body:
I want to dynamically change the style of a sap.m.CustomListItem of my list when I click on a button.

I used addStyleClass and it works only in the onInit method but not in the press` function, the style has been added but the view doesn't change.

Controller

pressbutton: function(oEvent) {
  var o = oEvent.getParameter("value");
  MessageToast.show(o.toString());
  var listitem = this.getView().byId("IDCustomerListItem");
  if (listitem.hasStyleClass("myListItemClass")) {
    this.getView().byId("IDCustomerListItem").removeStyleClass("myListItemClass");
    this.getView().byId("IDCustomerListItem").addStyleClass("myListItemClasso");
  } else {
    this.getView().byId("IDCustomerListItem").addStyleClass("myListItemClass");
  }
}

CSS

.myListItemClass {
  width: 50% !important;
  float: left;
}

.myListItemClasso {
  width: 100% !important;
}


问:
Add numbers to filename
I want to store data in different files. Therefore I want to create files as follows: data_1.log, data_2.log, ..., data_N.log. The appendix .log is not necessary but would be nice. All my approaches failed so far. Here is one sample that is probably close to what I need:

```<code>#include <stdio.h>
#include <string.h>

char get_file_name(int k){
    int i, j;
    char s1[100] = "logs/data_";
    char s2[100];
    snprintf(s2, 100, "%d", k);
    for(i = 0; s1[i] != '\0'; ++i);
    for(j = 0; s2[j] != '\0'; ++j, ++i){
        s1[i] = s2[j];
    }
    s1[i] = '\0';
    return s1;
}

int main(){

    char file_name[100];
    for(int k=0; k<10; k++){
        // Get data
        // ...
        // Create filename
        strcpy(file_name, get_file_name(k));
        printf("%s", file_name);
        // fp = fopen(file_name, "w+");
        // Write data to file
        // print_results_to_file();
        // fclose(fp);
    }

    return 0;
}
</code>```

At the moment I get the following errors which I don't understand:

```<code>    string.c: In function ‘get_file_name’:
string.c:14:12: warning: returning ‘char *’ from a function with return type ‘char’ makes integer from pointer without a cast [-Wint-conversion]
     return s1;
            ^~
string.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
string.c: In function ‘main’:
string.c:24:27: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
         strcpy(file_name, get_file_name(k));
                           ^~~~~~~~~~~~~~~~
In file included from string.c:2:
/usr/include/string.h:121:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
 extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
              ^~~~~~
</code>```

Is there a more simpler way to create such filenames? I can't believe that there isn't one.

答:
The function get_file_name has return type char

```<code>char get_file_name(int k){
</code>```

but it returns an object of type char *

```<code>char s1[100] = "logs/data_";
//...
return s1;
</code>```

Moreover the returned pointer points to a local array s1 that will not alive after exiting the function.

In this call

```<code>strcpy(file_name, get_file_name(k));
</code>```

the type of the second argument (that is char according to the function get_file_name declaration) shall be char *.

There is neither the function print_results_to_file declaration nor its definition.

According to the C Standard the function main without parameters shall be declared like

```<code>int main( void )
</code>```

I would write the function get_file_name the following way

```<code>#include <stdio.h>
#include <string.h>

char * get_file_name( char *file_name, size_t n, size_t padding )
{
    const char *common_part = "logs/data_";

    snprintf( file_name, n, "%s%zu", common_part, padding );

    return file_name;
}

int main( void )
{
    enum { N = 100 };
    char file_name[N];

    for ( size_t i = 0; i < 10; i++ ) puts( get_file_name( file_name, N, i ) );
}
</code>```

The program output is

```<code>logs/data_0
logs/data_1
logs/data_2
logs/data_3
logs/data_4
logs/data_5
logs/data_6
logs/data_7
logs/data_8
logs/data_9
</code>```

Title: Add numbers to filename

Body:
I want to store data in different files. Therefore I want to create files as follows: data_1.log, data_2.log, ..., data_N.log. The appendix .log is not necessary but would be nice. All my approaches failed so far. Here is one sample that is probably close to what I need:

#include <stdio.h>
#include <string.h>

char get_file_name(int k){
    int i, j;
    char s1[100] = "logs/data_";
    char s2[100];
    snprintf(s2, 100, "%d", k);
    for(i = 0; s1[i] != '\0'; ++i);
    for(j = 0; s2[j] != '\0'; ++j, ++i){
        s1[i] = s2[j];
    }
    s1[i] = '\0';
    return s1;
}

int main(){

    char file_name[100];
    for(int k=0; k<10; k++){
        // Get data
        // ...
        // Create filename
        strcpy(file_name, get_file_name(k));
        printf("%s", file_name);
        // fp = fopen(file_name, "w+");
        // Write data to file
        // print_results_to_file();
        // fclose(fp);
    }

    return 0;
}

At the moment I get the following errors which I don't understand:

    string.c: In function ‘get_file_name’:
string.c:14:12: warning: returning ‘char *’ from a function with return type ‘char’ makes integer from pointer without a cast [-Wint-conversion]
     return s1;
            ^~
string.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
string.c: In function ‘main’:
string.c:24:27: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
         strcpy(file_name, get_file_name(k));
                           ^~~~~~~~~~~~~~~~
In file included from string.c:2:
/usr/include/string.h:121:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
 extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
              ^~~~~~

Is there a more simpler way to create such filenames? I can't believe that there isn't one.

Body:
The function get_file_name has return type char

char get_file_name(int k){

but it returns an object of type char *

char s1[100] = "logs/data_";
//...
return s1;

Moreover the returned pointer points to a local array s1 that will not alive after exiting the function.

In this call

strcpy(file_name, get_file_name(k));

the type of the second argument (that is char according to the function get_file_name declaration) shall be char *.

There is neither the function print_results_to_file declaration nor its definition.

According to the C Standard the function main without parameters shall be declared like

int main( void )

I would write the function get_file_name the following way

#include <stdio.h>
#include <string.h>

char * get_file_name( char *file_name, size_t n, size_t padding )
{
    const char *common_part = "logs/data_";

    snprintf( file_name, n, "%s%zu", common_part, padding );

    return file_name;
}

int main( void )
{
    enum { N = 100 };
    char file_name[N];

    for ( size_t i = 0; i < 10; i++ ) puts( get_file_name( file_name, N, i ) );
}

The program output is

logs/data_0
logs/data_1
logs/data_2
logs/data_3
logs/data_4
logs/data_5
logs/data_6
logs/data_7
logs/data_8
logs/data_9


问:
Binding Generic Object (List<T>) to Custom Xamarin Control
I am developing a mobile app that has an API that I can call to get data, the majority of the endpoints are paged and return the following object:

```<code>public class PagedResult<T>
{
    public List<T> Data { get; private set; }

    public PagingInfo Paging { get; private set; }

    public PagedResult(IEnumerable<T> items, int pageNo, int pageSize, long totalRecordCount)
    {
        Data = new List<T>(items);
        Paging = new PagingInfo
        {
            PageNo = pageNo,
            PageSize = pageSize,
            TotalRecordCount = totalRecordCount,
            PageCount = totalRecordCount > 0
                ? (int)Math.Ceiling(totalRecordCount / (double)pageSize)
                : 0
        };
    }
}
</code>```

I have built a control that can select the paged results, the control presents a list of the current page items & allows the user to move through the other pages (pictured below).

I have built a proof of concept for this control however I have run into a small but really annoying stumbling block.

My PagedResult<T> is generic, but the PagedItemSource for my list view is not. I built the control to have the bindable properties: DataTemplate, PagedItemSource & LoadPageCommand. The control itself determines which page gets loaded & will execute that command itself (I may expose this value later but it's not needed for now).

When building the control I had to initialise the PagedResult<T>, however instead of worrying about generics I just made it into PagedResult<object> and did the same in my view model. Now i'm at the point where I want this list to be generic, part of the reason I built this control was to be generic and abstract as much responsibility for the paging to the control. However due to the fact that my API model uses a generic, I've gotten stuck!

I cannot initialise my control with a Generic T:

```<code>public partial class PaginationControl<T>: ContentView
{
    ...
}
</code>```

Will mean that the C# compiler starts shouting at me, the whole class goes beserk in fact. My binded properties display the warning: Static field in generic type. This is why I just used <object> as the type of my list, unfortunately the binding won't work in the following scenario:

View Model

```<code>public PagedResult<MyObject> PagedItemSource { get; set; }
</code>```

Control

```<code>public static readonly BindableProperty PagedItemSourceProperty = BindableProperty.Create(
    nameof(PagedItemSource),
    typeof(PagedResult<object>),
    typeof(PaginationControl),
    defaultValue: null,
    propertyChanged: (bindable, oldVal, newVal) => ((PaginationControl)bindable).OnPagedItemSourceChanged((PagedResult<object>)newVal)
);
</code>```

It will work if my view model's data is also of type <object> however thats no use because now I need to track the type of my data in my view model...

I've come up with a hacky work around so that I can crack on with the app, but it's stupid and feels dirty and I hate it...

My hack is to have a second property in my view model which just takes the current PagedResult<T> and converts it to PagedResult<object>, and binding this property to the control. (Sorry you had to read this)

I went and had a trawl for the Xamarin.Forms source code to see how they did this for ListView since it's essentially the same issue & their ListView accepts any generic object. Unfortunately I found the src incredibly confusing and learned nothing that would help solve my issue (I saw in ItemView<Cell> that ItemSource is an IEnumerable but I couldnt figure out how they were setting the T of this...

Any help would be much appreciated, I'm probably looking at this in the wrong way!

答:
As Ed Plunkett already mentioned you're thinking about the wrong way.

ItemsSource is of type IEnumerable there's no generic argument there since the ListView does not care about the specific type of items. This should be the case for your control as well, otherwise you wouldn't make it generic.

So why not just follow the same design they implement for most collections, List<T> for example also implements IList<T> and IList as interfaces. the last interface can be used when you're not interested in the generic argument but just want access to the list. Following this setup we can make something like this:

```<code>public interface IPagedResult
{
    IEnumerable Data { get; }

    PagingInfo Paging { get; }

    //any other properties you might need
}
</code>```

Then we can declare PagedResult like this:

```<code>public class PagedResult<T> : IPagedResult
{
    public List<T> List { get; private set; }
    public IEnumerable Data => List;

    public PagingInfo Paging { get; private set; }

    public PagedResult(IEnumerable<T> items, int pageNo, int pageSize, long totalRecordCount)
    {
        List = new List<T>(items);
        Paging = new PagingInfo
        {
            PageNo = pageNo,
            PageSize = pageSize,
            TotalRecordCount = totalRecordCount,
            PageCount = totalRecordCount > 0
                ? (int)Math.Ceiling(totalRecordCount / (double)pageSize)
                : 0
        };
    }
}
</code>```

And now you should just be able to declare your BindableProperty like this:

```<code>public static readonly BindableProperty PagedItemSourceProperty = BindableProperty.Create(
    nameof(PagedItemSource),
    typeof(IPagedResult),
    typeof(PaginationControl),
    defaultValue: null,
    propertyChanged: (bindable, oldVal, newVal) => ((PaginationControl)bindable).OnPagedItemSourceChanged((IPagedResult)newVal)
);
</code>```

And from this bindable property you can access the data list but also the paging information.

Hope this helps.

Body:
I am developing a mobile app that has an API that I can call to get data, the majority of the endpoints are paged and return the following object:

public class PagedResult<T>
{
    public List<T> Data { get; private set; }

    public PagingInfo Paging { get; private set; }

    public PagedResult(IEnumerable<T> items, int pageNo, int pageSize, long totalRecordCount)
    {
        Data = new List<T>(items);
        Paging = new PagingInfo
        {
            PageNo = pageNo,
            PageSize = pageSize,
            TotalRecordCount = totalRecordCount,
            PageCount = totalRecordCount > 0
                ? (int)Math.Ceiling(totalRecordCount / (double)pageSize)
                : 0
        };
    }
}

I have built a control that can select the paged results, the control presents a list of the current page items & allows the user to move through the other pages (pictured below).

I have built a proof of concept for this control however I have run into a small but really annoying stumbling block.

My PagedResult<T> is generic, but the PagedItemSource for my list view is not. I built the control to have the bindable properties: DataTemplate, PagedItemSource & LoadPageCommand. The control itself determines which page gets loaded & will execute that command itself (I may expose this value later but it's not needed for now).

When building the control I had to initialise the PagedResult<T>, however instead of worrying about generics I just made it into PagedResult<object> and did the same in my view model. Now i'm at the point where I want this list to be generic, part of the reason I built this control was to be generic and abstract as much responsibility for the paging to the control. However due to the fact that my API model uses a generic, I've gotten stuck!

I cannot initialise my control with a Generic T:

public partial class PaginationControl<T>: ContentView
{
    ...
}

Will mean that the C# compiler starts shouting at me, the whole class goes beserk in fact. My binded properties display the warning: Static field in generic type. This is why I just used <object> as the type of my list, unfortunately the binding won't work in the following scenario:

View Model

public PagedResult<MyObject> PagedItemSource { get; set; }

Control

public static readonly BindableProperty PagedItemSourceProperty = BindableProperty.Create(
    nameof(PagedItemSource),
    typeof(PagedResult<object>),
    typeof(PaginationControl),
    defaultValue: null,
    propertyChanged: (bindable, oldVal, newVal) => ((PaginationControl)bindable).OnPagedItemSourceChanged((PagedResult<object>)newVal)
);

It will work if my view model's data is also of type <object> however thats no use because now I need to track the type of my data in my view model...

I've come up with a hacky work around so that I can crack on with the app, but it's stupid and feels dirty and I hate it...

My hack is to have a second property in my view model which just takes the current PagedResult<T> and converts it to PagedResult<object>, and binding this property to the control. (Sorry you had to read this)

I went and had a trawl for the Xamarin.Forms source code to see how they did this for ListView since it's essentially the same issue & their ListView accepts any generic object. Unfortunately I found the src incredibly confusing and learned nothing that would help solve my issue (I saw in ItemView<Cell> that ItemSource is an IEnumerable but I couldnt figure out how they were setting the T of this...

Any help would be much appreciated, I'm probably looking at this in the wrong way!

Body:
As Ed Plunkett already mentioned you're thinking about the wrong way.

ItemsSource is of type IEnumerable there's no generic argument there since the ListView does not care about the specific type of items. This should be the case for your control as well, otherwise you wouldn't make it generic.

So why not just follow the same design they implement for most collections, List<T> for example also implements IList<T> and IList as interfaces. the last interface can be used when you're not interested in the generic argument but just want access to the list. Following this setup we can make something like this:

public interface IPagedResult
{
    IEnumerable Data { get; }

    PagingInfo Paging { get; }

    //any other properties you might need
}

Then we can declare PagedResult like this:

public class PagedResult<T> : IPagedResult
{
    public List<T> List { get; private set; }
    public IEnumerable Data => List;

    public PagingInfo Paging { get; private set; }

    public PagedResult(IEnumerable<T> items, int pageNo, int pageSize, long totalRecordCount)
    {
        List = new List<T>(items);
        Paging = new PagingInfo
        {
            PageNo = pageNo,
            PageSize = pageSize,
            TotalRecordCount = totalRecordCount,
            PageCount = totalRecordCount > 0
                ? (int)Math.Ceiling(totalRecordCount / (double)pageSize)
                : 0
        };
    }
}

And now you should just be able to declare your BindableProperty like this:

public static readonly BindableProperty PagedItemSourceProperty = BindableProperty.Create(
    nameof(PagedItemSource),
    typeof(IPagedResult),
    typeof(PaginationControl),
    defaultValue: null,
    propertyChanged: (bindable, oldVal, newVal) => ((PaginationControl)bindable).OnPagedItemSourceChanged((IPagedResult)newVal)
);

And from this bindable property you can access the data list but also the paging information.

Hope this helps.


问:
How to avoid multiple button click at same time in android?
I'm using two button in view. While clicking two button simultaneously it will goes to different activity at a time. How to avoid this?

I have tried like this, But its not working please save....

```<code>public class MenuPricipalScreen extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.menu_principal_layout);

    findViewById(R.id.imageView2).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView3));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    SelectYourLanguageVideo.class);
            startActivity(intent);
        }
    });
    findViewById(R.id.imageView3).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView2));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    CategoryScreen.class);
            intent.putExtra("request", "false");
            startActivity(intent);
        }
    });

}

 @Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    ((ImageView) findViewById(R.id.imageView3)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView2)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView3)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView2)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView3)).setFocusable(true);
    ((ImageView) findViewById(R.id.imageView2)).setFocusable(true);
}

 private void disable(View v) {
    Log.d("TAG", "TAG" + v.getId());
    v.setEnabled(false);
    v.setClickable(false);
    v.setFocusable(false);
}
}
</code>```

Thanks,

答:
for any one using data-binding :</p>

```<code>@BindingAdapter("onClickWithDebounce")
fun onClickWithDebounce(view: View, listener: android.view.View.OnClickListener) {
    view.setClickWithDebounce {
        listener.onClick(view)
    }
}

object LastClickTimeSingleton {
    var lastClickTime: Long = 0
}

fun View.setClickWithDebounce(action: () -> Unit) {
    setOnClickListener(object : View.OnClickListener {

        override fun onClick(v: View) {
            if (SystemClock.elapsedRealtime() - LastClickTimeSingleton.lastClickTime < 500L) return
            else action()
            LastClickTimeSingleton.lastClickTime = SystemClock.elapsedRealtime()
        }
    })
}

<androidx.appcompat.widget.AppCompatButton
                    ..
  android:text="@string/signup_signin"
  app:onClickWithDebounce="@{() -> viewModel.onSignUpClicked()}"
                   ... />
</code>```

Body:
I'm using two button in view. While clicking two button simultaneously it will goes to different activity at a time. How to avoid this?

I have tried like this, But its not working please save....

public class MenuPricipalScreen extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.menu_principal_layout);

    findViewById(R.id.imageView2).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView3));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    SelectYourLanguageVideo.class);
            startActivity(intent);
        }
    });
    findViewById(R.id.imageView3).setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

            disable(findViewById(R.id.imageView2));

            Intent intent = new Intent(MenuPricipalScreen.this,
                    CategoryScreen.class);
            intent.putExtra("request", "false");
            startActivity(intent);
        }
    });

}

 @Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    ((ImageView) findViewById(R.id.imageView3)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView2)).setEnabled(true);
    ((ImageView) findViewById(R.id.imageView3)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView2)).setClickable(true);
    ((ImageView) findViewById(R.id.imageView3)).setFocusable(true);
    ((ImageView) findViewById(R.id.imageView2)).setFocusable(true);
}

 private void disable(View v) {
    Log.d("TAG", "TAG" + v.getId());
    v.setEnabled(false);
    v.setClickable(false);
    v.setFocusable(false);
}
}

Thanks,

Body:
for any one using data-binding :

@BindingAdapter("onClickWithDebounce")
fun onClickWithDebounce(view: View, listener: android.view.View.OnClickListener) {
    view.setClickWithDebounce {
        listener.onClick(view)
    }
}

object LastClickTimeSingleton {
    var lastClickTime: Long = 0
}

fun View.setClickWithDebounce(action: () -> Unit) {
    setOnClickListener(object : View.OnClickListener {

        override fun onClick(v: View) {
            if (SystemClock.elapsedRealtime() - LastClickTimeSingleton.lastClickTime < 500L) return
            else action()
            LastClickTimeSingleton.lastClickTime = SystemClock.elapsedRealtime()
        }
    })
}

<androidx.appcompat.widget.AppCompatButton
                    ..
  android:text="@string/signup_signin"
  app:onClickWithDebounce="@{() -> viewModel.onSignUpClicked()}"
                   ... />


问:
Unable to consume WCF WSHttpBinding in .net core
I'am trying to move my project from .net to .net core. I  was initially using WCF WSHttpBinding service in .net but I'am unable to consume the same in .net core. I tried using BasicHttpBinding to connect with WsHttpBinding on the client side, but it throws an error saying the Bindings should match on both client and server side.

Suggest how to implement WSHttpBinding on .Net Core without modifying
WSHttpBindings on the client side.?

答:
This is a more complete answer and may help someone who is trying to call a SOAP service endpoint using .NET Core (.NET Core 2.2) and is struggling to get it working.

For the answer I'm assuming you've already added a Connected Service. If not, please refer to this Microsoft Article

The example below is using a BasicHttpBinding with an Ntlm Credential Type (DOMAIN\Username):

```<code>public async Task<string> ImportSalesOrder(string jsonString)
{
    var binding = new BasicHttpsBinding();
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;

    var endpoint = new EndpointAddress(_appConfig["endpoint"]);

    var client = new eCommIntegrationMgt_PortClient(binding, endpoint);

    client.ClientCredentials.UserName.UserName = _appConfig["usernam"];
    client.ClientCredentials.UserName.Password = _appConfig["password"];

    try
    {
        var result = await client.ImportSalesOrderAsync(jsonString);

        return result.return_value;
    }
    catch (Exception)
    {
        throw;
    }
}
</code>```

_appConfig is a global variable, which is made available via DI (Dependency Injection). You can replace them with hard-coded values if you're not making use of DI. The catch is redundant here, but you can add your custom error handling/logging.

eCommIntegrationMgt_PortClient is the client i.e. the Service object where all our endpoints exist.

Body:
This is a more complete answer and may help someone who is trying to call a SOAP service endpoint using .NET Core (.NET Core 2.2) and is struggling to get it working.

For the answer I'm assuming you've already added a Connected Service. If not, please refer to this Microsoft Article

The example below is using a BasicHttpBinding with an Ntlm Credential Type (DOMAIN\Username):

public async Task<string> ImportSalesOrder(string jsonString)
{
    var binding = new BasicHttpsBinding();
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;

    var endpoint = new EndpointAddress(_appConfig["endpoint"]);

    var client = new eCommIntegrationMgt_PortClient(binding, endpoint);

    client.ClientCredentials.UserName.UserName = _appConfig["usernam"];
    client.ClientCredentials.UserName.Password = _appConfig["password"];

    try
    {
        var result = await client.ImportSalesOrderAsync(jsonString);

        return result.return_value;
    }
    catch (Exception)
    {
        throw;
    }
}

_appConfig is a global variable, which is made available via DI (Dependency Injection). You can replace them with hard-coded values if you're not making use of DI. The catch is redundant here, but you can add your custom error handling/logging.

eCommIntegrationMgt_PortClient is the client i.e. the Service object where all our endpoints exist.


问:
Is it possible to find and style one character in a span with pure CSS?
I think the answer here is "no", but some of the tricks css3 pseudo selectors can be harnassed to perform come close to magic at times.

I want to find and style the period character inside spans. Don't ask why, the context is ridiculous. Sadly the character can't be relied upon to exist in the same position on each occasion, so it has to be found. I think without JS this can't be done but wanted to confirm.

答:
Overall no... however you could wrap each character in an element, which you can then style.

A simple bit of JS can be used to do this.

const el = document.querySelector("#find-periods");
el.innerHTML = el.innerHTML.replace(/\./g, '.')```
<pre class="snippet-code-css lang-css prettyprint-override"><code>.char-period{ color: red; font-size: 30px; }</code>```

  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae tristique massa, ut convallis risus. Vestibulum maximus sed libero ut lacinia. Integer vel mollis ex. Nullam mattis ipsum in massa aliquet pharetra eget nec enim. In vitae sem at nibh mollis finibus. Quisque id pretium velit. Donec nec augue volutpat, sodales dui id, eleifend augue. Nulla lobortis congue est ut venenatis. Ut mollis nisi ac purus auctor, nec sollicitudin mi vestibulum. Integer tincidunt, metus sit amet euismod porta, nisl nisi accumsan lectus, id lacinia nunc arcu vitae massa. Nunc et tellus ante. In mattis ex sed sem hendrerit elementum. Ut leo libero, convallis sit amet massa et, tincidunt malesuada augue. Pellentesque consectetur maximus maximus. Duis suscipit dolor risus, sed egestas libero iaculis ac. Phasellus consectetur quam ipsum, in finibus leo fringilla a.

```

Body:
Overall no... however you could wrap each character in an element, which you can then style.

A simple bit of JS can be used to do this.

const el = document.querySelector("#find-periods");
el.innerHTML = el.innerHTML.replace(/\./g, '<span class="char-period">.</span>')

.char-period{ color: red; font-size: 30px; }

<p id="find-periods">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae tristique massa, ut convallis risus. Vestibulum maximus sed libero ut lacinia. Integer vel mollis ex. Nullam mattis ipsum in massa aliquet pharetra eget nec enim. In vitae sem at nibh mollis finibus. Quisque id pretium velit. Donec nec augue volutpat, sodales dui id, eleifend augue. Nulla lobortis congue est ut venenatis. Ut mollis nisi ac purus auctor, nec sollicitudin mi vestibulum. Integer tincidunt, metus sit amet euismod porta, nisl nisi accumsan lectus, id lacinia nunc arcu vitae massa. Nunc et tellus ante. In mattis ex sed sem hendrerit elementum. Ut leo libero, convallis sit amet massa et, tincidunt malesuada augue. Pellentesque consectetur maximus maximus. Duis suscipit dolor risus, sed egestas libero iaculis ac. Phasellus consectetur quam ipsum, in finibus leo fringilla a.
</p>