android contentprovider api,Content Provider Basics

一个内容提供者访问数据的中央资源库。提供者是应用程序的一部分,提供自己的操作数据的UI。然而,内容提供者主要是被其他应用程序引用,通过提供者客户对象访问提供者。提供者和提供者客户端为数据提供一个一致的,标准的接口,也处理进程间的联系和数据安全访问。

本文讨论下面几个方面的基础:

内容提供类如何工作。

从内容提供者获取数据的API。

向内容提供者你插入、更新、删除数据的API。

便利的使用内容提供者的API。

Overview

提供者向应用程序呈现数据就像一个或多张表,就像是在关系数据库里一样。一行显示一些数据类型的实例,列的每行显示实例数据集合的独立数据。

例如:一个在android平台里内建的提供者是用户词典,用来存储用户想保存的非标准的拼写。表一说明了在提供者的表里数据是如何的:

Table 1: Sample user dictionary table.

word

app id

frequency

locale

_ID

mapreduce

user1

100

en_US

1

precompiler

user14

200

fr_FR

2

applet

user2

225

fr_CA

3

const

user1

255

pt_BR

4

int

user5

100

en_UK

5

在表1里,每行的单词都是在标准词典里找不到的。没列有一些和单词相关的数据,比如:它所属的区域。列头是列的名字。引用列的区域,你可以引用它的locale列。对于提供者来讲,自动认为列的_ID是“主键”。

注意:提供者并不是一定需要主键,它不需要使用_ID 作为主键的列名如果已经存在。然而,如果你想绑定一个提供者到一个ListView,一个列名是需要_ID的。对于这个需要的解释,在这里:Displaying query results。

访问一个提供者

一个应用程序通过客户类ContentResolver访问内容提供者的数据。这个函数有一个在提供者对象里同名的函数,是一个ContentProvider子类的实例。函数ContentResolver提供”CRUD”的基础(创建,获取,更新,删除)函数。

拥有提供者的应用程序进程的ContentResolver对象和ContentProvider对象可以自动处理进程间的数据交换。

注意:访问一个提供者,应用程序通常在manifest文件里请求指定的权限。在Content Provider Permissions一节里有更多细节。

例如,从User Dictionary Provider获取单词的一列和语言环境,你调用ContentResolver.query().query()函数调用定义的函数[ ContentProvider.query()]。下面的代码显示的是一个[ ContentResolver.query()]调用:

// Queries the user dictionary and returns results

mCursor = getContentResolver().query(

UserDictionary.Words.CONTENT_URI, // The content URI of the words table

mProjection, // The columns to return for each row

mSelectionClause // Selection criteria

mSelectionArgs, // Selection criteria

mSortOrder); // The sort order for the returned rows

Table 2 shows how the arguments to

Table 2: Query() compared to SQL query.

query() argument

SELECT keyword/parameter

Notes

Uri

FROM table_name

Uri maps to the table in the provider named table_name.

projection

col,col,col,...

projection is an array of columns that should be included for each row

retrieved.

selection

WHERE col = value

selection specifies the criteria for selecting rows.

selectionArgs

(No exact equivalent. Selection arguments replace ? placeholders in the

selection clause.)

sortOrder

ORDER BY col,col,...

sortOrder specifies the order in which rows appear in the returned

Content URIs

一个内容URI是一个定于数据的URI。内容URI包含一个提供者的符号名(它的权限)和一个指向一个表(一个路径)的名字。当你调用客户端函数来访问表的时候,这个URI是参数的一个。

上面的代码,常量CONTENT_URI包含user dictionary的单词表的内容URI。对象ContentResolver 解析URI的权限,使用它。ContentResolver能分派查询参数来更正提供者。

使用内容URI的部分路径来选择想访问的表。提供者的每个外在的表都有一个路径。

之前的代码,“words”表完整的URI是:

content://user_dictionary/words

字符串user_dictionary是提供者的权限,字符串words是表的路径。字符串content://(配置)通常指示标识这项是一个内容URI。

提供者允许你通过附加在URI后的一个ID值来访问表的一行。例如,从获取_ID是4的一行,你可以使用内容URI:

Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

通常获取一个行集合的时候使用id并且想要更新或者删除它们中的一个。

注意:类Uri和Uri.Builder包含便利的函数来从一个字符串格式化Uri对象。ContetnUris包含一个便利的函数withAppendedId()来向URI最近一个id。之前的片段是用来追加id到Userdictionary。

从提供者里获取数据

从提供者里获取数据,例子使用User Dictionary Provider。

为了清晰,这一节的代码段在“UI线程”里调用ContentResolver.query()。实际的代码,然而,你需要在分开的线程里做异步查询。可以使用CursorLoader实现,更多的信息在Loaders 指南。代码很短;他们没有显示一个完整的应用。

获取数据,有以下的两个步骤:

1、需要提供者允许读访问。

2、发送一个query到提供者的代码。

请求读访问权限

从提供者获取数据,应用程序需要“读许可”。不可以在运行的时候申请;在你的manifest文件里声明,使用元素扩展权限名,它是提供者定义的。

当你在manifest里声明元素,实际上你就是申请权限。当用户安装引用程序,也就隐式的授予了请求。

为你使用的提供者查找确切的读访问权限的名字,就像其它提供者的访问权限的名字一样,参考提供者文档。

在Content Provider Permissions一节,有关于访问提供者的权限的更多信息。

User Dictionary Provider在manifest文件里定义android.permission.READ_USER_DICTIONARY权限,应用程序想从提供者读取需要这个权限。

构造查询

下一步获取数据时提供者构造一个查询。第一个片段为访问User Dictionary Provider定义了一些变量:

// A "projection" defines the columns that will be returned for each row

String[] mProjection =

{

UserDictionary.Words._ID, // Contract class constant for the _ID column name

UserDictionary.Words.WORD, // Contract class constant for the word column name

UserDictionary.Words.LOCALE // Contract class constant for the locale column name

};

// Defines a string to contain the selection clause

String mSelectionClause = null;

// Initializes an array to contain selection arguments

String[] mSelectionArgs = {""};

下面的代码显示如何使用ContentResolver.query(),例子使用。提供者客户端查询是类似SQL查询,它返回一个列的集合,选择标准集,排序命令。

查询需要返回的列的集合被疑个Projection(变量mProjection)调用。知道获取行的表达式是分到一个选择语句和一个选择参数里的。选择语句是一个逻辑、布尔值、列名、值(变量mSelection)复合表达式。如果你指定替换参数?来代替一个值,查询函数从选择参数数列里获取值(变量mSelectionArgs)。

下面的片段,如果用户不输入一个单词,设置为null,查询返回提供者里所有的单词。如果用户输入一个单词,设置 UserDictionary.Words.Word + " = ?" 并且选择参数数组的第一个元素设置为用户输入的。

/*

* This defines a one-element String array to contain the selection argument.

*/

String[] mSelectionArgs = {""};

// Gets a word from the UI

mSearchString = mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

// If the word is the empty string, gets everything

if (TextUtils.isEmpty(mSearchString)) {

// Setting the selection clause to null will return all words

mSelectionClause = null;

mSelectionArgs[0] = "";

} else {

// Constructs a selection clause that matches the word that the user entered.

mSelectionClause = UserDictionary.Words.WORD + " = ?";

// Moves the user's input string to the selection arguments.

mSelectionArgs[0] = mSearchString;

}

// Does a query against the table and returns a Cursor object

mCursor = getContentResolver().query(

UserDictionary.Words.CONTENT_URI, // The content URI of the words table

mProjection, // The columns to return for each row

mSelectionClause // Either null, or the word the user entered

mSelectionArgs, // Either empty, or the string the user entered

mSortOrder); // The sort order for the returned rows

// Some providers return null if an error occurs, others throw an exception

if (null == mCursor) {

/*

* Insert code here to handle the error. Be sure not to use the cursor! You may want to

* call android.util.Log.e() to log this error.

*

*/

// If the Cursor is empty, the provider found no matches

} else if (mCursor.getCount() < 1) {

/*

* Insert code here to notify the user that the search was unsuccessful. This isn't necessarily

* an error. You may want to offer the user the option to insert a new row, or re-type the

* search term.

*/

} else {

// Insert code here to do something with the results

}

这个查询和SQL语句类似。

SELECT _ID, word, frequency, locale FROM words WHERE word = ORDER BY word ASC;

这个SQL语句,实际的列名用于替代合约类的常量。

防止恶意插入

如果通过提供者管理的数据在SQL数据库里,包括外部不可信的数据进入原始的SQL语句会导致SQL注入。 考虑这种情况:

Consider this selection clause:

// Constructs a selection clause by concatenating the user's input to the column name

String mSelectionClause = "var = " + mUserInput;

如果你这样做,你就允许用户串联恶意的SQL到你的SQL语句里。例如:用户可以为mUserInput输入“nothing; DROP TABLE *;”结果选择语句var = nothing; DROP TABLE *;

当选择语句被认为是一个SQL语句,就会引起提供者擦除SQLite数据库里所有的表(除非提供者设置捕获SQL injection 的语句)。

为了解决这个问题,使用一个有?作为可替换参数的选择语句和一个分开的选择参数数组。这样做,用户输入一个**到查询而不是作为SQL语句的一部分被中断。因为,它没有被视为是SQL,用户输入不可以注入恶意的SQL。使用如下的选择语句,而不是使用级联用户输入的语句。

// Constructs a selection clause with a replaceable parameter

String mSelectionClause = "var = ?";

设置选择参数数组如下:

// Defines an array to contain the selection arguments

String[] selectionArgs = {""};

设置一个选择参数数组就如下:

// Sets the selection argument to the user's input

selectionArgs[0] = mUserInput;

?是可替换参数,选择查询数组首选的方法是指定一节,甚至提供者不基于一个SQL数据库。

显示查询结果

ContentResolver.query() 函数总是返回一个Cursor ,它包含查询的Projection指定的列,行是匹配查询选择标准的。一个Cursor 对象提供随机的读行权限还有它包含的列。使用Cursor 函数,你可以在结果里遍历行,决定每列的数据类型,获取列外的数据,使用结果的其它属性。一些Cursor 实现当提供者数据变化时自动的更新。或当Cursor 改变是触发观察对象的方法,或者两者都有。

注意:一个提供者可能限制访问列基于对象的属性来生成查询。例如:合约提供者访问一些列来同步适配器,因此它不返回到Activity或一个服务。

如果没有匹配选择标准的行,提供者返回一个Cursor对象,它的Cursor.getCount() 是0(一个空的cursor)。

如果内部发生一个错误,查询结果依靠指定的提供者。可能选择返回null,或者抛出异常。

如果Cursor是行的列表,显示Cursor内容的方法是把它通过SimpleCursorAdapter和一个ListView连接。

下面的代码是前面代码的继续。它创建一个对象SimpleCursorAdapter包含通过查询获取的Cursor,设置这个对象作为ListView的适配器。

// Defines a list of columns to retrieve from the Cursor and load into an output row

String[] mWordListColumns =

{

UserDictionary.Words.WORD, // Contract class constant containing the word column name

UserDictionary.Words.LOCALE // Contract class constant containing the locale column name

};

// Defines a list of View IDs that will receive the Cursor columns for each row

int[] mWordListItems = { R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter

mCursorAdapter = new SimpleCursorAdapter(

getApplicationContext(), // The application's Context object

R.layout.wordlistrow, // A layout in XML for one row in the ListView

mCursor, // The result from the query

mWordListColumns, // A string array of column names in the cursor

mWordListItems, // An integer array of view IDs in the row layout

0); // Flags (usually none are needed)

// Sets the adapter for the ListView

mWordList.setAdapter(mCursorAdapter);

注意:备份一个ListView和一个Cursor,curso需要包含一个列名叫_ID。因为,查询显示之前返回的单词表的_ID列,甚至ListView不显示。这也解释了为什么每个表的列有一个_ID。

从查询结果里获取数据

不是简单显示你查询的结果,你可使用它们做别的任务。例如:你可以从user dictionary获取拼写并且在其它提供者里查询。可以在Cursor里遍历行:

// Determine the column index of the column named "word"

int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);

/*

* Only executes if the cursor is valid. The User Dictionary Provider returns null if

* an internal error occurs. Other providers may throw an Exception instead of returning null.

*/

if (mCursor != null) {

/*

* Moves to the next row in the cursor. Before the first movement in the cursor, the

* "row pointer" is -1, and if you try to retrieve data at that position you will get an

* exception.

*/

while (mCursor.moveToNext()) {

// Gets the value from the column.

newWord = mCursor.getString(index);

// Insert code here to process the retrieved word.

...

// end of while loop

}

} else {

// Insert code here to report an error if the cursor is null or the provider threw an exception.

}

Cursor实现一系列的“get”函数,为从对象获取不同类型的数据。例如:前面的代码使用函数getString()。getType()函数返回一个表示数据类型的值。

内容提供者权限

一个内容提供者可以指明其它需要访问数据的程序的权限。权限确保用户知道程序想要访问的数据。基于提供者的请求,程序请求权限以此访问提供者。当安装应用程序的时候,终端用户看到请求权限。 如果提供者的程序不指明权限,其它应用程序不可以访问数据。然而,提供者程序的组件拥有所有的读写权,不管有没有指定。

之前提到的,User Dictionary Provider请求android.permission.READ_USER_DICTIONARY 权限来获取数据。提供者为插入、更新、删除数据分开android.permission.WRITE_USER_DICTIONARY 权限。

获取访问提供者访问的权限,一个应用程序需要在manifest文件里有元素。当Android包管理器安装应用程序,用户必须同意程序请求的所有权限。如果用户允许,包管理器继续安装;如果用户不允许,包管理器终止安装。 下面的元素请求User Dictionary Provider读访问。

关于提供者权限的影响,更多的信息在Security and Permissions 。

插入,更新,删除数据

一些你从提供者获取数据的方法,你使用提供者客户端和提供者的ContentProvider 来修改数据。你调用函数**。提供者和提供者客户端自动处理安全和进程间通信。

插入数据

向一个提供者插入数据,你可以调用。这个函数插入一个新的行,返回该行的内容URI。以下代码显示如何向一个User Dictionary Provider插入新行:

这里有代码

代码段不需要添加-ID列,因为列的维护是自动的。如果提供者给每个添加的行分配一个独一无二的-ID值。提供者使用这个值作为表的主键。

newUri 返回的内容URI指明新增加的行,使用如下格式:

content://user_dictionary/words/

The is the contents of _ID for the new row.

Most providers can detect this form of content URI automatically and then perform the requested

operation on that particular row.

To get the value of _ID from the returned

Updating data

To update a row, you use a null.

The following snippet changes all the rows whose locale has the language "en" to a

have a locale of null. The return value is the number of rows that were updated:

// Defines an object to contain the updated values

ContentValues mUpdateValues = new ContentValues();

// Defines selection criteria for the rows you want to update

String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?";

String[] mSelectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows

int mRowsUpdated = 0;

...

/*

* Sets the updated value and updates the selected words.

*/

mUpdateValues.putNull(UserDictionary.Words.LOCALE);

mRowsUpdated = getContentResolver().update(

UserDictionary.Words.CONTENT_URI, // the user dictionary content URI

mUpdateValues // the columns to update

mSelectionClause // the column to select on

mSelectionArgs // the value to compare to

);

You should also sanitize user input when you call

Protecting against malicious input.

Deleting data

Deleting rows is similar to retrieving row data: you specify selection criteria for the rows

you want to delete and the client method returns the number of deleted rows.

The following snippet deletes rows whose appid matches "user". The method returns the

number of deleted rows.

// Defines selection criteria for the rows you want to delete

String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";

String[] mSelectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted

int mRowsDeleted = 0;

...

// Deletes the words that match the selection criteria

mRowsDeleted = getContentResolver().delete(

UserDictionary.Words.CONTENT_URI, // the user dictionary content URI

mSelectionClause // the column to select on

mSelectionArgs // the value to compare to

);

You should also sanitize user input when you call

Protecting against malicious input.

Provider Data Types

Content providers can offer many different data types. The User Dictionary Provider offers only

text, but providers can also offer the following formats:

integer

long integer (long)

floating point

long floating point (double)

Another data type that providers often use is Binary Large OBject (BLOB) implemented as a

64KB byte array. You can see the available data types by looking at the

The data type for each column in a provider is usually listed in its documentation.

The data types for the User Dictionary Provider are listed in the reference documentation

for its contract class Contract Classes).

You can also determine the data type by calling

Providers also maintain MIME data type information for each content URI they define. You can

use the MIME type information to find out if your application can handle data that the

provider offers, or to choose a type of handling based on the MIME type. You usually need the

MIME type when you are working with a provider that contains complex

data structures or files. For example, the

The section MIME Type Reference describes the

syntax of both standard and custom MIME types.

Alternative Forms of Provider Access

Three alternative forms of provider access are important in application development:

Batch access: You can create a batch of access calls with methods in

the

Asynchronous queries: You should do queries in a separate thread. One way to do this is to

use a Loaders guide demonstrate

how to do this.

Data access via intents: Although you can't send an intent

directly to a provider, you can send an intent to the provider's application, which is

usually the best-equipped to modify the provider's data.

Batch access and modification via intents are described in the following sections.

Batch access

Batch access to a provider is useful for inserting a large number of rows, or for inserting

rows in multiple tables in the same method call, or in general for performing a set of

operations across process boundaries as a transaction (an atomic operation).

To access a provider in "batch mode",

you create an array of authority to this

method, rather than a particular content URI, which allows each

The description of the Contact Manager

sample application contains an example of batch access in its ContactAdder.java

source file.

Displaying data using a helper app

If your application does have access permissions, you still may want to use an

intent to display data in another application. For example, the Calendar application accepts an

Calendar Provider guide.

The application to which you send the intent doesn't have to be the application

associated with the provider. For example, you can retrieve a contact from the

Contact Provider, then send an

Data access via intents

Intents can provide indirect access to a content provider. You allow the user to access

data in a provider even if your application doesn't have access permissions, either by

getting a result intent back from an application that has permissions, or by activating an

application that has permissions and letting the user do work in it.

Getting access with temporary permissions

You can access data in a content provider, even if you don't have the proper access

permissions, by sending an intent to an application that does have the permissions and

receiving back a result intent containing "URI" permissions.

These are permissions for a specific content URI that last until the activity that receives

them is finished. The application that has permanent permissions grants temporary

permissions by setting a flag in the result intent:

Note: These flags don't give general read or write access to the provider

whose authority is contained in the content URI. The access is only for the URI itself.

A provider defines URI permissions for content URIs in its manifest, using the

Security and Permissions guide,

in the section "URI Permissions".

For example, you can retrieve data for a contact in the Contacts Provider, even if you don't

have the

Your application sends an intent containing the action

Because this intent matches the intent filter for the

People app's "selection" activity, the activity will come to the foreground.

In the selection activity, the user selects a

contact to update. When this happens, the selection activity calls

Your activity returns to the foreground, and the system calls your activity's

With the content URI from the result intent, you can read the contact's data

from the Contacts Provider, even though you didn't request permanent read access permission

to the provider in your manifest. You can then get the contact's birthday information

or his or her email address and then send the e-greeting.

Using another application

A simple way to allow the user to modify data to which you don't have access permissions is to

activate an application that has permissions and let the user do the work there.

For example, the Calendar application accepts an

Contract Classes

A contract class defines constants that help applications work with the content URIs, column

names, intent actions, and other features of a content provider. Contract classes are not

included automatically with a provider; the provider's developer has to define them and then

make them available to other developers. Many of the providers included with the Android

platform have corresponding contract classes in the package

For example, the User Dictionary Provider has a contract class

String[] mProjection =

{

UserDictionary.Words._ID,

UserDictionary.Words.WORD,

UserDictionary.Words.LOCALE

};

Another contract class is

MIME Type Reference

Content providers can return standard MIME media types, or custom MIME type strings, or both.

MIME types have the format

type/subtype

For example, the well-known MIME type text/html has the text type and

the html subtype. If the provider returns this type for a URI, it means that a

query using that URI will return text containing HTML tags.

Custom MIME type strings, also called "vendor-specific" MIME types, have more

complex type and subtype values. The type value is always

vnd.android.cursor.dir

for multiple rows, or

vnd.android.cursor.item

for a single row.

The subtype is provider-specific. The Android built-in providers usually have a simple

subtype. For example, the when the Contacts application creates a row for a telephone number,

it sets the following MIME type in the row:

vnd.android.cursor.item/phone_v2

Notice that the subtype value is simply phone_v2.

Other provider developers may create their own pattern of subtypes based on the provider's

authority and table names. For example, consider a provider that contains train timetables.

The provider's authority is com.example.trains, and it contains the tables

Line1, Line2, and Line3. In response to the content URI

content://com.example.trains/Line1

for table Line1, the provider returns the MIME type

vnd.android.cursor.dir/vnd.example.line1

In response to the content URI

content://com.example.trains/Line2/5

for row 5 in table Line2, the provider returns the MIME type

vnd.android.cursor.item/vnd.example.line2

Most content providers define contract class constants for the MIME types they use. The

Contacts Provider contract class

Content URIs for single rows are described in the section

Content URIs.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】医学影像调窗技术!!!!

转自&#xff1a;https://www.cnblogs.com/assassinx/p/3139505.html 在年初的时候做过一个dicom格式文件解析&#xff0c;当时只是提了下。看着跟别人的显示出来也差不多 其实是我想太简单了。整理了下思路 这里提供正确的调窗代码。 医学影像 说得挺高科技的 其实在这个过程…

开始-运行 下常用快捷命令

在“开始”菜单上单击“运行“&#xff0c;输入 1. eventvwr&#xff0e;msc /s 打开事件查看器 &#xff08;可查看系统日志&#xff09; 2.gpedit.msc 打开组策略 示例&#xff1a;在Windows Server 2003中关闭系统事件跟踪程序: 单击“开始→运行”&#xff0c;输入gped…

解决6410 WINCE6 应用层调用SetSystemPowerState api关机无效的问题

6410平台下的wince6系统&#xff0c;在应用层中使用SetSystemPowerState api函数关机发现无效。 应用层调用如下&#xff1a; [cpp]view plaincopy SetSystemPowerState(NULL, POWER_STATE_OFF, POWER_FORCE); 注&#xff1a;该调用需要引用pm.h头文件&#xff0c;该头文件在…

【转】理解字节序 大端字节序和小端字节序

转自&#xff1a;https://www.cnblogs.com/gremount/p/8830707.html 以下内容参考了 http://www.ruanyifeng.com/blog/2016/11/byte-order.html https://blog.csdn.net/yishengzhiai005/article/details/39672529 1. 计算机硬件有两种储存数据的方式&#xff1a;大端字节序…

Web-DispatcherServletUrlPatterns

Web-DispatcherServletUrlPatterns 在MANIFEST.MF文件中指定了Web-DispatcherServletUrlPatterns时千万要注意它的规则&#xff0c;首先它必须是符合servlet的url-pattern的&#xff0c;其规则如下&#xff1a; 在web.xml文件中&#xff0c;以下语法用于定义映射&#xff1a; …

WCHAR char CString等常用类型互转

1、CString to WCHAR*: [cpp]view plaincopy WCHAR *wch (WCHAR*)str.GetBuffer(str.GetLength()); str为CString类型。 2、WCHRA* to char*: [cpp]view plaincopy memset(buf, 0, bufInLen); // WCHRA to char WideCharToMultiByte( CP_ACP, 0, wch, -1, buf,…

html文件自动批阅器怎么设计,作业作业提交与批改系统HTML界面.doc

作业作业提交与批改系统HTML界面作业1-作业提交与批改系统HTML界面请根据以下需求部分功能或全部全部功能HTML界面代码&#xff1b;注意HTML代码附在本文后面一、作业提交与批改系统系统功能图基本功能1&#xff0e;学生注册2&#xff0e;学生、教师、管理员密码找回功能3&…

【转】Photoshop保存格式介绍大全

01 PSD格式 PSD格式&#xff1a;PSD是Photoshop默认的文件格式&#xff0c;他可以保留文档中的所有图层、蒙蔽、通道、路径、未栅格化的文字、图层样式等。通常情况下&#xff0c;我们都是将文件保存为PSD格式&#xff0c;以后可以对其修改。PSD是除大型文档格式&#xff08;PS…

创建windows服务,定时监控网站应用程序池

最近网站总是报"Timer_Connection"错误,导致该网站所使用的应用程序池由于错误过多停止运行,网站也就出现了service unvaliable,无法访问,在网上查了很多资料,结果很让人无奈,这个问题已经困扰我了很久,一直没有得到解决,后来同事发来一篇文章让我有了新的解决方法,虽…

UNICODE十六进制数组转成中英文

UNICODE十六进制的数组转成中英文 实现char*转换成中英文&#xff0c;每两个char合成一个wchar_t&#xff1a; [cpp]view plaincopy // UNICODE十六进制数组转成中英文 // hex array to wchar_t* // wchs NULL, wchsLen as output(the size of wchs will be used) // er…

html+选择弹出选项卡,javascript – Chrome扩展程序:从弹出窗口获取当前选项卡

我正在撰写Chrome扩展程序&#xff0c;在其中一部分&#xff0c;当弹出页面上的按钮被点击时&#xff0c;我需要获取当前选项卡的标题和URL。我之前已经和Chrome的消息传递系统一起工作了&#xff0c;并且经过许多努力&#xff0c;已经设法让它在许多场合工作。不过&#xff0c…

【转】Qtcreator中常用快捷键和小技巧

转自&#xff1a;https://blog.csdn.net/imxiangzi/article/details/48863855 https://blog.csdn.net/jh1513/article/details/52346802 快捷键及对应含义 下载地址&#xff1a;http://download.csdn.net/detail/jh1513/9615209 快捷键 功能 Esc 切换到代码编辑状态 F1 …

添加蜂窝注册表及永久存储

1、 添加 Hive-based Registry 在 Platform Builder 的“ Catalog ”窗口中&#xff0c;单击打开 Catalog->Core OS->Windows ce devices->File Systems and Data Store->Registry Storage(Choose 1)->Hive-based-based Registry 节点&#xff0c;选中 Hive-b…

interface abstract与virtual

interface用来声明接口 1.只提供一些方法规约&#xff0c;不提供方法主体 如 public interface IPerson { void getName();//不包含方法主体 } 2.方法不能用public abstract等修饰,无字段变量&#xff0c;无构造函数。 3.方法可包含参数 如 public interface IP…

【转】VS编译时自动引用Debug|Release版本的dll

转自&#xff1a;https://www.cnblogs.com/KevinYang/archive/2011/04/10/2011879.html 公司一些早期的项目&#xff0c;把所有工程都放到一个解决方案下了&#xff0c;导致整个解决方案编译很慢&#xff0c;而且也不便于类库的复用和维护。因此我们决定把工程按照功能划分到不…

asp 生成html文件,将指定的asp文件内容生成html文件_asp技巧

Function GetPage(url)dim RetrievalSet Retrieval CreateObject(“Microsoft.XMLHTTP”)With Retrieval.Open “Get”, url, False , “”, “”.SendGetPage BytesToBstr(.ResponseBody)End WithSet Retrieval NothingEnd FunctionFunction BytesToBstr(body)dim objstrea…

Delphi手动创建数据集

习惯了.net的DataTable&#xff0c;便习惯性的认为Delphi中也有类似的东西&#xff0c;结果搞了好久才搞定&#xff0c;看来看去是拿着Delphi实现.net的思想&#xff0c;生搬硬套了&#xff0c;不过倒也解决了一些问题语言间的思想差别还是有的呃。 1数据集的创建CreatDataSet…

WINCE基于hive注册表的实现

1.WINCE注册表概述 WINCE注册表保存着应用程序、驱动、用户参数配置和其他配置设定的数据&#xff0c;WINCE提供自由选择基于RAM还是基于hive的注册表&#xff0c;其中基于RAM注册表本质是堆栈文件&#xff0c;保存在RAM中&#xff0c;如果RAM的供电掉电了&#xff0c;除非OEM…

【转】DICOM之Print!!!!!!!!!

转自&#xff1a;https://blog.csdn.net/weixin_41556165/article/details/81064531 基本概念&#xff1a; Film:在DICOM协议中使用Film来统称不同的Hard Copy&#xff0c;例如photographic film和paper。 DICOM Print的数据流由Print Session、Print Job、Print&#xff08;h…

静态html js文件上传,js实现动态添加上传文件页面

发邮件是需要添加一些文件&#xff0c;每添加一个文件&#xff0c;页面上可以显示一个表单文件上传选项。此功能为&#xff1a;初始时刻只有一个添加按钮&#xff0c;当点击添加文件时&#xff0c;会增加一个选择文件和删除区域&#xff0c;同时显示上传按钮&#xff0c;当点击…