24/05/2018, 20:43

Searching with RecordFilter

Ngoài việc sắp xếp các record (sử dụng RecordComparator), enumerator còn cung cấp cơ chế lọc (tìm kiếm các record thỏa mãn một điều kiện nào đó). Khi sử dụng RecordComparator tất cả các record trong RecordStore đều được lưu trong một result set. Nhưng khi ...

Ngoài việc sắp xếp các record (sử dụng RecordComparator), enumerator còn cung cấp cơ chế lọc (tìm kiếm các record thỏa mãn một điều kiện nào đó). Khi sử dụng RecordComparator tất cả các record trong RecordStore đều được lưu trong một result set. Nhưng khi dùng RecordFilter, chỉ có những thỏa mãn điều kiện mới có trong enumerator result set.

class SearchFilter implements RecordFilter

{

private String searchText = null;

public SearchFilter(String searchText)

{

// This is the text to search for

this.searchText = searchText.toLowerCase();

}

public boolean matches(byte[] candidate)

{

String str = new String(candidate).toLowerCase();

// Look for a match

if (searchText != null && str.indexOf(searchText) != -1)

return true;

else

}

}

return false;

Trên đây là một class đơn giản thực thi interface RecordFilter. Class này sẽ được gắn với một enumerator, và khi đó enumerator sẽ dùng hàm matches() duyệt hết recordstore lấy ra những record cần tìm:

// Create a new search filter

SearchFilter search = new SearchFilter("search text");

// Reference the filter when creating the result set RecordEnumeration re = rs.enumerateRecords(search,null,false);

// If there is at least one record in result set, a match was found

if (re.numRecords() > 0)

// Do something

Sau đây ta sẽ xem qua chương trình tìm kiếm đơn giản sử dụng interface RecordFilter: Ví dụ 6:

/*--------------------------------------------------

* SimpleSearch.java

*

* Display a Form and Textbox for searching records

* Each record contains a String object.

*

* Uses: Enumeration, RecordFilter

*-------------------------------------------------*/

import java.io.*;

import javax.microedition.midlet.*; import javax.microedition.rms.*; import javax.microedition.lcdui.*;

public class SimpleSearch extends MIDlet implements CommandListener

{

private Display display; // Reference to Display object private Form fmMain; // The main form

private StringItem siMatch; // The matching text, if any

private Command cmFind; // Command to search record store private Command cmExit; // Command to insert items

private TextField tfFind; // Search text as requested by user

private RecordStore rs = null; // Record store

static final String REC_STORE = "db_6"; // Name of record store

public SimpleSearch()

{

display = Display.getDisplay(this);

// Define textfield, stringItem and commands

tfFind = new TextField("Find", "", 10, TextField.ANY);

siMatch = new StringItem(null, null);

cmExit = new Command("Exit", Command.EXIT, 1);

cmFind = new Command("Find", Command.SCREEN, 2);

// Create the form, add commands fmMain = new Form("Record Search");

fmMain.addCommand(cmExit);

fmMain.addCommand(cmFind);

// Append textfield and stringItem

fmMain.append(tfFind);

fmMain.append(siMatch);

// Capture events

fmMain.setCommandListener(this);

//--------------------------------

// Open and write to record store

//--------------------------------

openRecStore(); // Create the record store writeTestData(); // Write a series of records

}

public void destroyApp( boolean unconditional )

{

closeRecStore(); // Close record store

deleteRecStore();

}

public void startApp()

{

display.setCurrent(fmMain);

}

public void pauseApp()

{

}

public void openRecStore()

{

try

{

// Create record store if it does not exist

rs = RecordStore.openRecordStore(REC_STORE, true );

}

catch (Exception e)

{

db(e.toString());

}

}

public void closeRecStore()

{

try

{

rs.closeRecordStore();

}

catch (Exception e)

{

db(e.toString());

}

}

public void deleteRecStore()

{

if (RecordStore.listRecordStores() != null)

{

try

{

RecordStore.deleteRecordStore(REC_STORE);

}

catch (Exception e)

{

db(e.toString());

}

}

}

/*--------------------------------------------------

* Create array of data to write into record store

*-------------------------------------------------*/

public void writeTestData()

{

String[] golfClubs = {

"Wedge...good from the sand trap",

"Truong dai hoc khoa hoc tu nhien",

"Putter...only on the green",

"Hoc mon LTUDM rat bo ich!"};

writeRecords(golfClubs);

}

/*--------------------------------------------------

* Write to record store.

*-------------------------------------------------*/

public void writeRecords(String[] sData)

{

byte[] record;

try

{

// Only add the records once

if (rs.getNumRecords() > 0)

return;

for (int i = 0; i < sData.length; i++)

{

record = sData[i].getBytes();

rs.addRecord(record, 0, record.length);

}

}

catch (Exception e)

{

db(e.toString());

}

}

/*--------------------------------------------------

* Search using enumerator and record filter

*-------------------------------------------------*/

private void searchRecordStore()

{

try

{

// Record store is not empty

if (rs.getNumRecords() > 0)

{

// Setup the search filter with the user requested text

SearchFilter search =

new SearchFilter(tfFind.getString());

RecordEnumeration re =

rs.enumerateRecords(search, null, false);

// A match was found using the filter

if (re.numRecords() > 0)

// Show match in the stringItem on the form

siMatch.setText(new String(re.nextRecord()));

re.destroy(); // Free enumerator

}

}

catch (Exception e)

{

db(e.toString());

}

}

public void commandAction(Command c, Displayable s)

{

if (c == cmFind)

{

searchRecordStore();

}

else if (c == cmExit)

{

destroyApp(false);

notifyDestroyed();

}

}

/*--------------------------------------------------

* Simple message to console for debug/errors

* When used with Exceptions we should handle the

* error in a more appropriate manner.

*-------------------------------------------------*/

private void db(String str)

{

System.err.println("Msg: " + str);

}

}

/*--------------------------------------------------

* Search for text within a record

* Each record passed in contains only text (String)

*-------------------------------------------------*/

class SearchFilter implements RecordFilter

{

private String searchText = null;

public SearchFilter(String searchText)

{

// This is the text to search for

this.searchText = searchText.toLowerCase();

}

public boolean matches(byte[] candidate)

{

String str = new String(candidate).toLowerCase();

// Look for a match

if (searchText != null && str.indexOf(searchText) != -1)

return true;

else

return false;

}

}

Sau khi viết class SearchFilter, ta tạo một instance search, khi khai báo class RecordEnumeration sẽ tham chiếu đến instance trên. Khi đó chỉ có những record thỏa mãn điều kiện (trong hàm matches()) mới hiển thị trong result set:

// Setup the search filter with the user requested text

SearchFilter search = new SearchFilter(tfFind.getString()); RecordEnumeration re =rs.enumerateRecords(search,null,false);

// A match was found using the filter if (re.numRecords() > 0)

siMatch.setText(new String(re.nextRecord()));

Output:

Lưu ý ví dụ trên không phân biệt chữ hoa thường.

Tiếp theo đây chúng ta lại xét thêm một ví dụ về tìm kiếm record. Ví dụ 7:

/*--------------------------------------------------

* SearchStreams.java

*

* Display a Form and Textbox for searching records

* Each record contains multiple Java data types -

* (String, boolean and integer). Use the String

* data for searching

*

* Uses: Enumeration, RecordFilter

*-------------------------------------------------*/

import java.io.*;

import javax.microedition.midlet.*; import javax.microedition.rms.*; import javax.microedition.lcdui.*;

public class SearchStreams extends MIDlet implements CommandListener

{

private Display display; // Reference to Display object private Form fmMain; // The main form

private StringItem siMatch; // The matching text, if any

private Command cmFind; // Command to search record store private Command cmExit; // Command to insert items

private TextField tfFind; // Search text

private RecordStore rs = null; // Record store

static final String REC_STORE = "db_7"; // Name of record store

public SearchStreams()

{

display = Display.getDisplay(this);

// Define textfield, stringItem and commands

tfFind = new TextField("Find", "", 10, TextField.ANY);

siMatch = new StringItem(null, null);

cmExit = new Command("Exit", Command.EXIT, 1);

cmFind = new Command("Find", Command.SCREEN, 2);

// Create the form, add commands fmMain = new Form("Record Search");

fmMain.addCommand(cmExit);

fmMain.addCommand(cmFind);

// Append textfield and stringItem

fmMain.append(tfFind);

fmMain.append(siMatch);

// Capture events

fmMain.setCommandListener(this);

//--------------------------------

// Open and write to record store

//--------------------------------

openRecStore(); // Create the record store writeTestData(); // Write a series of records

}

public void destroyApp( boolean unconditional )

{

closeRecStore(); // Close record store

deleteRecStore();

}

public void startApp()

{

display.setCurrent(fmMain);

}

public void pauseApp()

{

}

public void openRecStore()

{

try

{

// Create record store if it does not exist

rs = RecordStore.openRecordStore(REC_STORE, true );

}

catch (Exception e)

{

db(e.toString());

}

}

public void closeRecStore()

{

try

{

rs.closeRecordStore();

}

catch (Exception e)

{

db(e.toString());

}

}

public void deleteRecStore()

{

if (RecordStore.listRecordStores() != null)

{

try

{

RecordStore.deleteRecordStore(REC_STORE);

}

catch (Exception e)

{

db(e.toString());

}

}

}

/*--------------------------------------------------

* Create three arrays to write into record store

*-------------------------------------------------*/

public void writeTestData()

{

String[] pets = {"duke - big, goofy golden retriever",

"tiger - we found in a field",

"spike - loves chasing car tires",

"beauregard - barks at everything"}; boolean[] dog = {true, false, true, true}; int[] rank = {3, 0, 1, 2};

writeStream(pets, dog, rank);

}

/*--------------------------------------------------

* Write to record store using streams.

*-------------------------------------------------*/

public void writeStream(String[] sData, boolean[] bData,int[] iData)

{

try

{

// Only add the records once

if (rs.getNumRecords() > 0)

return;

// Write data into an internal byte array

ByteArrayOutputStream strmBytes =

new ByteArrayOutputStream();

// Write Java data types into the above byte array

DataOutputStream strmDataType =

new DataOutputStream(strmBytes);

byte[] record;

for (int i = 0; i < sData.length; i++)

{

// Write Java data types

strmDataType.writeUTF(sData[i]);

strmDataType.writeBoolean(bData[i]);

strmDataType.writeInt(iData[i]);

// Clear any buffered data

strmDataType.flush();

// Get stream data into byte array and write record

record = strmBytes.toByteArray();

rs.addRecord(record, 0, record.length);

// Toss any data in the internal array so writes

// starts at beginning (of the internal array)

strmBytes.reset();

}

strmBytes.close();

strmDataType.close();

}

catch (Exception e)

{

db(e.toString());

}

}

/*--------------------------------------------------

* Search using enumerator and record filter

*-------------------------------------------------*/

private void searchRecordStore()

{

try

{

// Record store is not empty

if (rs.getNumRecords() > 0)

{

// Setup the search filter with the user requested text

SearchFilter search =

new SearchFilter(tfFind.getString());

RecordEnumeration re =

rs.enumerateRecords(search, null, false);

// A match was found using the filter

if (re.numRecords() > 0)

{

// Read from the specified byte array

ByteArrayInputStream strmBytes =

new ByteArrayInputStream(re.nextRecord());

// Read Java data types from the above byte array

DataInputStream strmDataType =

new DataInputStream(strmBytes);

// Show matching result in stringItem component on form

siMatch.setText(strmDataType.readUTF());

search.searchFilterClose(); // Close record filter

strmBytes.close(); // Close stream

strmDataType.close(); // Close stream

re.destroy(); // Free enumerator

}

}

}

catch (Exception e)

{

db(e.toString());

}

}

public void commandAction(Command c, Displayable s)

{

if (c == cmFind)

{

searchRecordStore();

}

else if (c == cmExit)

{

destroyApp(false);

notifyDestroyed();

}

}

/*--------------------------------------------------

* Simple message to console for debug/errors

* When used with Exceptions we should handle the

* error in a more appropriate manner.

*-------------------------------------------------*/

private void db(String str)

{

System.err.println("Msg: " + str);

}

}

/*--------------------------------------------------

* Search for text within a record

* Each record passed in contains multiple Java data

* types (String, boolean and integer)

*-------------------------------------------------*/

class SearchFilter implements RecordFilter

{

private String searchText = null;

// Read from a specified byte array

private ByteArrayInputStream strmBytes = null;

// Read Java data types from the above byte array private DataInputStream strmDataType = null; public SearchFilter(String searchText)

{

// This is the text to search for

this.searchText = searchText.toLowerCase();

}

// Cleanup

public void searchFilterClose()

{

try

{

if (strmBytes != null)

strmBytes.close();

if (strmDataType != null)

strmDataType.close();

}

catch (Exception e)

{

}

}

public boolean matches(byte[] candidate)

{

String str = null;

try

{

strmBytes = new ByteArrayInputStream(candidate);

strmDataType = new DataInputStream(strmBytes);

// Although 3 pieces of data were written to

// the record (String, boolean and integer)

// we only need one read because the string to

// search is the first "field" in the record

str = strmDataType.readUTF().toLowerCase();

}

catch (Exception e)

{

return false;

}

// Look for a match

if (str != null && str.indexOf(searchText) != -1)

return true;

else

return false;

}

}

Cùng có chức năng tìm kiếm nhưng ví dụ 7 khác ví dụ 6 ở chỗ dữ liệu lưu vào record. Ở ví dụ này dữ liệu lưu vào record dưới dạng dãy byte, và trong dãy byte này ta lại lưu nhiều trường dữ liệu:

strmDataType.writeUTF(sData[i]); // Write Strings strmDataType.writeBoolean(bData[i]); // Write booleans strmDataType.writeInt(iData[i]); // Write integers

Trong hàm searchRecordStore() ta tạo một bộ tìm kiếm và enumerator. Phương thức matches() (của class SearchFilter) sẽ được gọi bởi enumerator và được áp dụng cho mỗi record trong RecordStore. Để đọc được đúng dữ liệu cần dùng ta cần dùng hai stream – một dùng để đọc dãy byte trong record và một dùng để đọc đúng kiểu dữ liệu trong dãy byte đó.

strmBytes = new ByteArrayInputStream(candidate); strmDataType = new DataInputStream(strmBytes); str = strmDataType.readUTF().toLowerCase();

Sau đó chuỗi này sẽ được so sánh với searchText: if (str != null && str.indexOf(searchText) != -1) return true;

else

return false;

Output:

0